So funktioniert es
- Ihre Software sendet
POST /api/v1/einvoicesmit einem Bearer-Token (siehe Ein Bearer-Token erhalten) und der Rechnung als JSON. - Der Server prüft die Daten, berechnet fehlende Summen und ordnet jeden Wert den Feldern seines Rechnungsformulars zu (standardmäßig das Formular
zugferd). - Das Formular wird über die normale Formularverarbeitung abgesendet. Sie erzeugt das XML nach EN 16931 (Cross Industry Invoice, ZUGFeRD- / Factur-X-Profil EN 16931, geschrieben nach den KoSIT-Regeln der XRechnung), bettet es in ein PDF/A-3 ein und versiegelt das PDF.
- Das PDF geht an Ihre Software zurück (als Base64 im JSON oder mit
Accept: application/pdfals Datei) und, wie beim Webformular, per E-Mail an den Geschäftsinhaber des Formulars und an die E-Mail-Adressen in der Rechnung (Verkäufer und Käufer).
"action": "preview" endet nach Schritt 2: Sie erhalten das ausgefüllte Rechnungsformular als PDF, nichts wird versiegelt oder versandt. Damit prüfen Sie Layout und Zuordnung.
Kleinste Anfrage
Rechnungsnummer, Verkäufer, Käufer und mindestens eine Position sind Pflicht. Das Rechnungsdatum ist standardmäßig heute, die Währung die Vorgabe des Formulars (EUR beim Beispielformular), alle Summen werden berechnet.
curl -X POST https://forms.example.com/api/v1/einvoices \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -H "Accept: application/pdf" \
-o rechnung.pdf -d '{
"invoice": { "number": "2026-0042", "taxPercent": 19 },
"seller": { "name": "Example Supplies GmbH", "street": "Musterstraße 1", "postCode": "10115", "town": "Berlin", "country": "DE", "vatId": "DE123456789" },
"buyer": { "name": "Example Hotel AG", "street": "Seestraße 1", "postCode": "12345", "town": "Musterstadt", "country": "DE" },
"items": [ { "name": "Beratung (Stunden)", "quantity": 4, "netPrice": 120 } ]
}'Vollständiges Beispiel (XRechnung)
Eine Rechnung an eine deutsche Behörde mit Leitweg-ID, Kontaktdaten, Lieferdatum und SEPA-Zahlung. Datumsangaben nach ISO 8601 (yyyy-MM-dd; dd.MM.yyyy wird auch angenommen), Beträge als Zahlen mit Punkt als Dezimaltrennzeichen.
{
"action": "submit",
"invoice": {
"number": "2026-0042", "date": "2026-10-11", "currency": "EUR",
"dueDate": "2026-10-25", "deliveryDate": "2026-10-09", "paymentTerms": "14 Tage netto",
"buyerReference": "04011000-12345-34", "buyerOrderReference": "PO-7781",
"taxPercent": 19, "taxCategory": "S", "note": "Vielen Dank für Ihren Auftrag."
},
"seller": { "name": "Example Supplies GmbH", "contactName": "Erika Muster", "street": "Musterstraße 1",
"postCode": "10115", "town": "Berlin", "country": "DE", "phone": "+49 30 1234567",
"email": "billing@example.com", "vatId": "DE123456789" },
"buyer": { "name": "Stadt Musterstadt", "contactName": "Max Beispiel", "street": "Rathausplatz 1",
"postCode": "12345", "town": "Musterstadt", "country": "DE", "email": "rechnungen@example.org" },
"payment": { "iban": "DE02120300000000202051", "bic": "BYLADEM1001", "accountName": "Example Supplies GmbH" },
"items": [
{ "name": "Beratung (Stunden)", "quantity": 4, "netPrice": 120, "sellerAssignedId": "C-100" },
{ "name": "Reisekostenpauschale", "netPrice": 80 }
]
}Feldreferenz
Jedes JSON-Feld, der Geschäftsbegriff (BT) nach EN 16931, den es füllt, und der Feldname im Rechnungsformular. Pflichtfelder sind markiert.
| JSON | Bedeutung | EN 16931 | Formularfeld |
|---|---|---|---|
invoice.number Pflicht | Rechnungsnummer | BT-1 | InvoiceID |
invoice.date | Rechnungsdatum (Standard: heute) | BT-2 | date |
invoice.currency | Währung nach ISO 4217 (EUR, CHF, …) | BT-5 | InvoiceCurrencyCode |
invoice.dueDate | Fälligkeitsdatum | BT-9 | DueDate |
invoice.buyerReference | Käuferreferenz; bei XRechnung die Leitweg-ID | BT-10 | BuyerReference |
invoice.buyerOrderReference | Bestellnummer des Käufers | BT-13 | BuyerOrderReference |
invoice.paymentTerms | Zahlungsbedingungen als Text | BT-20 | PaymentTerms |
invoice.note | Rechnungshinweis | BT-22 | InvoiceNote |
invoice.deliveryDate | Tatsächliches Lieferdatum | BT-72 | DeliveryDate |
invoice.paymentReference | Verwendungszweck (nur wenn das Formular das Feld hat) | BT-83 | PaymentReference |
invoice.taxPercent | Umsatzsteuersatz in Prozent für die ganze Rechnung | BT-152 / BT-119 | TAXPercent |
invoice.taxCategory | Steuerkategorie: S, Z, E, AE oder G (siehe unten) | BT-151 / BT-118 | TaxCategory |
invoice.taxExemptionReason | Befreiungsgrund bei E, AE, G | BT-120 | TaxExemptionReason |
seller.name Pflicht | Name des Verkäufers | BT-27 | SellerName |
seller.street, street2 | Adresszeilen | BT-35, BT-36 | SellerStreet1, SellerStreet2 |
seller.postCode, town, country | PLZ, Ort, Land (ISO 3166-1, z. B. DE) | BT-38, BT-37, BT-40 | SellerPostCode, SellerTown, SellerCountry |
seller.vatId | Umsatzsteuer-Identifikationsnummer | BT-31 | SellerVAT |
seller.contactName, phone | Ansprechpartner und Telefon | BT-41, BT-42 | SellerPersonName, SellerPhone |
seller.email | E-Mail des Verkäufers als elektronische Adresse | BT-34 | SellerEmail |
buyer.name Pflicht | Name des Käufers | BT-44 | BuyerName |
buyer.street, street2, postCode, town, country | Adresse des Käufers | BT-50 bis BT-55 | BuyerStreet1 … BuyerCountry |
buyer.vatId | USt-IdNr. des Käufers | BT-48 | BuyerVAT |
buyer.contactName, phone | Ansprechpartner beim Käufer | BT-56, BT-57 | BuyerPersonName, BuyerPhone |
buyer.email | E-Mail des Käufers als elektronische Adresse | BT-49 | BuyerEmail |
payment.iban, bic, accountName | Bankverbindung für die SEPA-Überweisung | BT-84, BT-86, BT-85 | IBAN, BIC, AccountName |
items[].name Pflicht | Artikelbezeichnung | BT-153 | ItemName1, ItemName2, … |
items[].quantity | Menge (Standard 1, Einheit C62 = Stück) | BT-129 | BilledQuantity1, … |
items[].netPrice Pflicht | Nettoeinzelpreis | BT-146 | NetPriceProductTradePrice1, … |
items[].lineTotal | Nettobetrag der Position (Standard: Menge × Preis) | BT-131 | LineTotalAmount1, … |
items[].sellerAssignedId | Artikelnummer des Verkäufers (nur wenn das Formular das Feld hat) | BT-155 | SellerAssignedID1, … |
totals.lineTotal, taxTotal, grandTotal | Summen; werden berechnet, wenn sie fehlen | BT-106, BT-110, BT-112 | LineTotalAmount, TaxTotalAmount, GrandTotalAmount |
Beträge, Umsatzsteuer und Rundung
- Positionsbetrag = Menge × Nettopreis, auf 2 Nachkommastellen gerundet (kaufmännisch), außer Sie senden
lineTotal. - Summe der Positionen = Summe der Positionsbeträge; sie ist zugleich Bemessungsgrundlage und Gesamtbetrag ohne Umsatzsteuer.
- Umsatzsteuer = Summe der Positionen ×
taxPercent/ 100, auf 2 Stellen gerundet. Gesamtbetrag = Summe + Umsatzsteuer; der Zahlbetrag entspricht dem Gesamtbetrag. - Summen, die Sie in
totalssenden, haben Vorrang vor der Berechnung; so übernehmen Sie die exakten Zahlen Ihrer Buchhaltung. - Ein Steuersatz gilt für die ganze Rechnung. Bei mehreren Steuersätzen senden Sie je Satz eine Rechnung oder fragen Sie uns nach dem ZUGFeRD Pro SDK.
- Zahlen:
1234.5oder"1234.50". Ein Komma wird abgelehnt, so wird aus"12,50"nie 1250.
Steuerkategorien
SNormalsatz (Standard). Mit Satz 0 wird darausZ.ZNullsatz.Esteuerbefreit; ohnetaxExemptionReasonwird „Steuerfreie Leistung“ eingetragen.AEUmkehr der Steuerschuld (Code VATEX-EU-AE); Standardgrund „Steuerschuldnerschaft des Leistungsempfängers“.GAusfuhr außerhalb der EU (VATEX-EU-G).
Bei E, AE und G ist der Steuersatz 0.
Zahlung
Mit iban enthält die Rechnung eine SEPA-Überweisung (Zahlungsart 58) mit BIC und Kontoinhaber. Ohne IBAN ist die Zahlungsart „nicht angegeben“ (Code 1). Zahlungsbedingungen (paymentTerms) und Fälligkeit (dueDate) werden in jedem Fall geschrieben; ohne Fälligkeitsdatum gilt das Rechnungsdatum.
Checkliste XRechnung
Rechnungen an deutsche öffentliche Auftraggeber müssen der XRechnung entsprechen. Senden Sie mindestens:
invoice.buyerReference= die Leitweg-ID der Behörde (ohne sie schreibt der Server eine erzeugte Referenz, die eine Behörde ablehnt).seller.emailundbuyer.email(elektronische Adressen),seller.contactName,seller.phone.seller.vatId, vollständige Adressen mit Ländercodes,invoice.dueDateoderpaymentTerms.- Zahlungsdaten (
payment.iban), wenn die Behörde überweist.
Das XML wird nach den KoSIT-Regeln geschrieben. Prüfen Sie Ihre ersten Rechnungen einmal mit dem KoSIT-Validator oder einem Viewer Ihrer Wahl.
Die Antwort
201 Created mit der Einsendungs-ID, dem PDF und den verwendeten Summen:
HTTP/1.1 201 Created
{
"submissionId": "7f3c2a9e0d5b4e1fa2c8b6d4e9f01a23",
"formId": "zugferd",
"action": "submit",
"status": "submitted",
"pdf": { "fileName": "zugferd.pdf", "contentType": "application/pdf", "size": 152331,
"sha256": "…", "eInvoice": true, "data": "JVBERi0xLjc…" },
"totals": { "lineTotal": 560.00, "taxTotal": 106.40, "grandTotal": 666.40, "currency": "EUR" },
"notOnForm": [ "PaymentReference", "SellerAssignedID1", "SellerAssignedID2" ]
}
pdf.eInvoiceisttrue, wenn das E-Rechnungs-XML im PDF eingebettet ist.notOnFormnennt Werte, für die das gewählte Formular kein Feld hat (sie sind nicht Teil der Rechnung).- Mit
Accept: application/pdf(oder"returnPdf": "binary") ist die Antwort das PDF selbst; der HeaderX-Submission-Identhält die ID."returnPdf": "none"lässt die PDF-Daten weg. "action": "preview"antwortet mit 200 und der ausgefüllten, nicht versandten Rechnung.
Eigenes Rechnungsformular
Standardmäßig nutzt der Server sein Rechnungsformular (Einstellung Form for e-invoices, Vorgabe zugferd). Mit "formId" wählen Sie ein anderes, zum Beispiel eines mit Ihrem Briefkopf. Das Formular muss freigegeben sein und Felder mit den Namen aus der Feldreferenz haben; Positionen werden ab 1 (oder ab 0) nummeriert. Die Zahl der ItemName…-Felder ist die Höchstzahl der Positionen: Das Beispielformular hat 8.
Gestalten Sie das Formular im Editor, benennen Sie die Felder wie aufgeführt, geben Sie es frei und prüfen Sie die Zuordnung mit "action": "preview". GET /api/v1/forms/{formId}/fields zeigt die Feldnamen eines Formulars.
Grenzen und Fehler
Fehler kommen als Problem Details (application/problem+json); siehe auch die Fehlerliste der API.
| Status | Code | Bedeutung |
|---|---|---|
| 422 | validation_failed | Ein Pflichtwert fehlt (Nummer, Name von Verkäufer oder Käufer, Bezeichnung oder Preis einer Position), ein Datum oder eine Zahl ist nicht lesbar, oder ein Wert passt nicht zum Formular (z. B. unbekannte Währung oder Land in einer Auswahlliste). |
| 422 | too_many_items | Mehr Positionen, als das Formular aufnehmen kann. |
| 422 | not_an_invoice_form | Das gewählte Formular hat keine Positionsfelder. |
| 403 | role_required | Rechnungen erstellen erfordert die Rolle user oder admin. |
| 404 / 409 | form_not_found, form_not_released | Das Rechnungsformular gibt es für dieses Token nicht oder es ist nicht freigegeben. |
| 429 | rate_limited, daily_limit | Zu viele Anfragen oder Tagesgrenze der API-Einsendungen erreicht. |
| 502 | form_processing_failed | Die Rechnung konnte nicht erstellt oder versandt werden; nichts wurde zugestellt. |
Fragen und Antworten
Welches ZUGFeRD-Profil erzeugt die API?
Das Profil EN 16931 (in ZUGFeRD 1 COMFORT genannt): Cross-Industry-Invoice-XML, eingebettet in ein PDF/A-3, identisch mit Factur-X. Das XML wird nach den KoSIT-Regeln geschrieben, die auch die XRechnung verwendet.
Wie erstelle ich eine XRechnung?
Senden Sie die Leitweg-ID der Behörde als invoice.buyerReference und füllen Sie E-Mail-Adressen und Kontaktdaten von Verkäufer und Käufer aus. Die API erstellt dann eine Rechnung nach EN 16931, die den XRechnung-Regeln entspricht, eingebettet im PDF.
Kann ich die Summen aus meiner Buchhaltung übergeben?
Ja. Werte in totals (lineTotal, taxTotal, grandTotal) und items[].lineTotal haben Vorrang vor der Berechnung.
Wird die Rechnung automatisch per E-Mail versandt?
Ja, wie beim Rechnungs-Webformular: an den Geschäftsinhaber des Formulars und an die E-Mail-Adressen in den Daten. Mit "action": "preview" erhalten Sie das PDF ohne Versand.
Kann eine Rechnung mehrere Steuersätze haben?
Über diesen Endpunkt nicht: Ein Satz gilt für die ganze Rechnung. Senden Sie je Satz eine Rechnung oder nutzen Sie für komplexe Rechnungen das ZUGFeRD Pro SDK.
Ihre erste E-Rechnung erstellen
Fordern Sie Testzugangsdaten an und testen Sie die E-Rechnungs-API auf unserem Online-Server.
Stand: