XRechnung ist ein reines XML-Format nach EN 16931 (in den Syntaxen UBL und CII), das Behörden und viele große Abnehmer verlangen. Über eine API erzeugst du es in drei Schritten: Rechnung anlegen (der Server rechnet Summen und USt), ausstellen (Nummer wird atomar vergeben, das XML wird gerendert und validiert), XML abholen.
XRechnung ist das reine XML-Format der E-Rechnung: kein Sichtbeleg, nur strukturierte Daten nach EN 16931. Behörden (B2G) und viele große Abnehmer verlangen genau dieses Format. Hier ist der Flow, wie du eine gültige XRechnung per API erzeugst — ohne Codelisten, Geschäftsregeln und Profilstände selbst zu pflegen.
Der Flow: drei Calls
1) Rechnung anlegen. Du schickst Kunde und Positionen; Summen und USt rechnet der
Server. Der Idempotency-Key-Header macht Retries sicher — ein wiederholter
Draft-Create ist ein Replay, kein Duplikat.
POST /invoices
Authorization: Bearer sk_test_…
Idempotency-Key: 6f1c2a…
Content-Type: application/json
{
"currency": "EUR",
"documentTarget": "b2g",
"buyer": {
"name": "Stadt Fennbrück — Amt für Digitalisierung",
"addressLine1": "Marktstraße 12",
"postalCode": "24998", "city": "Fennbrück", "countryCode": "DE"
},
"buyerReference": "<LEITWEG-ID>",
"buyerElectronicAddress": "<LEITWEG-ID>",
"invoiceTypeCode": "380",
"lineItems": [
{ "description": "Wartung Fachverfahren Meldewesen (Q4 2026)", "quantity": "3",
"unitCode": "MON", "unitPriceNet": "1240.00", "taxRatePercent": "19" }
]
}Antwort: 201, Status "draft", alle Summen serverseitig berechnet. Beträge und
Mengen sind DECIMAL-Strings ("1250.00"), damit an Float-Rundung nichts verloren
geht.
2) Ausstellen. Das Finalisieren vergibt die Rechnungsnummer atomar, rendert das XRechnung-XML und validiert es gegen die EN-16931-Geschäftsregeln:
PATCH /invoices/{id}/finalize
Authorization: Bearer sk_test_…
# → Status "issued", Nummer vergeben, XRechnung-XML (CII) gerendert + validiert3) XML abholen. Das reine XRechnung-XML in CII-Syntax:
GET /invoices/{id}/xml
Authorization: Bearer sk_test_…
# → XRechnung 3.0, CIIBrauchst du zusätzlich einen menschenlesbaren Sichtbeleg, holst du dasselbe Dokument als hybrides ZUGFeRD/Factur-X über den PDF-Pfad — siehe ZUGFeRD 2.x / Factur-X per API erzeugen.
Welche XRechnung-Version herauskommt
Fortlauf erzeugt XRechnung 3.0.x (CustomizationID
urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0), CII-Syntax, geprüft
gegen die KoSIT-Prüfartefakte für 3.0.2.
Im XML steht diese Kennung als Spezifikationskennung (BT-24) in
rsm:ExchangedDocumentContext/ram:GuidelineSpecifiedDocumentContextParameter/ram:ID. Was
XRechnung 4.0 ändert und warum der 01.01.2027 kein Gültigkeitsdatum von 4.0 ist, steht unter
XRechnung 4.0 und EN 16931:2026.
Welches Feld wohin: vom Request ins CII-XML
Die Tabelle zeigt für die zentralen Felder aus POST /invoices, welchem Business Term (BT)
der EN 16931 sie entsprechen und in welches CII-Element der Renderer sie schreibt.
rsm:ExchangedDocument liegt direkt unter dem Wurzelelement rsm:CrossIndustryInvoice, die Gruppen
ram:ApplicableHeaderTrade… unter rsm:SupplyChainTradeTransaction. ram:BuyerTradeParty
liegt in ram:ApplicableHeaderTradeAgreement, die Positionsfelder in je einem
ram:IncludedSupplyChainTradeLineItem.
| Feld im Request | BT | CII-Element |
|---|---|---|
invoiceNo | BT-1 | rsm:ExchangedDocument/ram:ID |
issueDate | BT-2 | rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString |
invoiceTypeCode | BT-3 | rsm:ExchangedDocument/ram:TypeCode |
currency | BT-5 | ram:ApplicableHeaderTradeSettlement/ram:InvoiceCurrencyCode |
dueDate | BT-9 | ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms/ram:DueDateDateTime |
buyerReference | BT-10 | ram:ApplicableHeaderTradeAgreement/ram:BuyerReference |
paymentTerms | BT-20 | ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms/ram:Description |
notes | BT-22 | rsm:ExchangedDocument/ram:IncludedNote/ram:Content |
buyer.name | BT-44 | ram:BuyerTradeParty/ram:Name |
buyer.vatId | BT-48 | ram:BuyerTradeParty/ram:SpecifiedTaxRegistration/ram:ID |
buyerElectronicAddress | BT-49 | ram:BuyerTradeParty/ram:URIUniversalCommunication/ram:URIID |
buyer.city | BT-52 | ram:BuyerTradeParty/ram:PostalTradeAddress/ram:CityName |
buyer.postalCode | BT-53 | ram:BuyerTradeParty/ram:PostalTradeAddress/ram:PostcodeCode |
buyer.countryCode | BT-55 | ram:BuyerTradeParty/ram:PostalTradeAddress/ram:CountryID |
deliveryDate | BT-72 | ram:ApplicableHeaderTradeDelivery/ram:ActualDeliverySupplyChainEvent/ram:OccurrenceDateTime |
billingPeriodStart | BT-73 | ram:ApplicableHeaderTradeSettlement/ram:BillingSpecifiedPeriod/ram:StartDateTime |
billingPeriodEnd | BT-74 | ram:ApplicableHeaderTradeSettlement/ram:BillingSpecifiedPeriod/ram:EndDateTime |
lineItems[].quantity | BT-129 | ram:SpecifiedLineTradeDelivery/ram:BilledQuantity |
lineItems[].unitCode | BT-130 | ram:SpecifiedLineTradeDelivery/ram:BilledQuantity/@unitCode |
lineItems[].unitPriceNet | BT-146 | ram:SpecifiedLineTradeAgreement/ram:NetPriceProductTradePrice/ram:ChargeAmount |
lineItems[].vatCategory | BT-151 | ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:CategoryCode |
lineItems[].taxRatePercent | BT-152 | ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:RateApplicablePercent |
lineItems[].description | BT-153 | ram:SpecifiedTradeProduct/ram:Name |
lineItems[].itemDescription | BT-154 | ram:SpecifiedTradeProduct/ram:Description |
Was die Tabelle nicht zeigt, aber beim Integrieren zählt:
- Summen rechnet der Server. Totals im Request werden ignoriert; Netto, Steuer und Brutto entstehen aus den Positionen.
issueDatesetzt der Server: Das Rechnungsdatum ist immer der Tag der Ausstellung. Für das Leistungsdatum nimmst dudeliveryDateoder den ZeitraumbillingPeriodStart/billingPeriodEnd— beides zusammen lehnt die API ab.invoiceNoist optional. Ohne eigene Nummer vergibt Fortlauf sie beim Ausstellen.- Ohne
deliveryDatesteht das Rechnungsdatum in BT-72, ohnedueDatesetzt Fortlauf Rechnungsdatum plus 30 Tage als Fälligkeit. buyerElectronicAddressfällt aufbuyerEmailzurück. Das Schema in@schemeIDleitet der Dienst ab:0204für eine Leitweg-ID,EMfür eine E-Mail-Adresse — du trägst den Wert ohne Präfix ein.- Die XRechnung entsteht für
"documentTarget": "b2g". Dann sindbuyerReference(BR-DE-15) und eine gültige elektronische Adresse (BR-63) Pflicht; fehlen sie, lehnt Fortlauf das Ausstellen ab, bevor eine Nummer vergeben wird. Bei B2B ist das Ergebnis das ZUGFeRD-PDF mit eingebettetem CII-XML. vatCategorynimmt über die API derzeit nurSan. Die API-Referenz nennt das Feld BT-118, weil es die Kategorie der Steueraufschlüsselung bestimmt; auf Positionsebene ist es BT-151.
XRechnung, kurz erklärt
- Reines XML, keine PDF-Hülle. XRechnung transportiert nur strukturierte Daten; der Empfänger stellt sie bei Bedarf selbst dar.
- CII oder UBL. Beide Syntaxen erfüllen die EN 16931. Fortlauf erzeugt CII — dasselbe Modell, das auch im ZUGFeRD-Hybrid steckt, sodass beide Ausgaben aus einer Quelle entstehen.
- B2G-Besonderheiten. Im Behördenkontext adressiert die Leitweg-ID den
Empfänger (als
buyerReference, BT-10). Für inländisches B2B ist sie nicht nötig.
Validierung gehört dazu
Well-formed ist nicht valide: Eine XRechnung muss die Schematron-Regeln der EN 16931 und des XRechnung-Profils bestehen. Warum das mehr ist als korrektes XML, erklärt KoSIT-Validierung erklärt. Fortlauf erzeugt die Rechnung aus einem sauberen EN-16931-Datenmodell und validiert sie beim Ausstellen; besteht sie nicht, wird sie nicht ausgestellt.
Was heute schon läuft
- Sandbox & API-Keys — live: eigene Test-Keys (
sk_test_) und eine vollständige Sandbox. Den Zugang legst du dir selbst an — kostenlos, ohne Karte: Produkt-Einstieg für Entwickler →.
Archivierung
Die strukturierten Originale legt Fortlauf unverändert und schreibgeschützt ab (WORM) — mit Validierungsbericht, Sendeprotokoll und vollständigem Export. Das unterstützt GoBD-konforme Archivierung; mehr unter GoBD-Archivierung von E-Rechnungen.
Der gezeigte Code ist illustrativ. Die Base-URL und die vollständige Feld-Referenz stehen offen im API-Referenzbereich — ohne Anmeldung. Die API-Kategorie im Überblick steht unter E-Rechnung per API.
Selbst ausprobieren? Der Zugang ist kostenlos und ohne Karte — Produkt-Einstieg für Entwickler →
Oder den eigenen Abrechnungsfluss konkret durchsprechen: 30 Min, technisch, mit dem Gründer →