Warum JSON statt direktem XML-Editing? Eine ehrliche Antwort für Entwickler.
EN 16931 ist kein deutscher Standard — es ist ein europäisches Regelwerk, das eine präzise XML-Schicht vorschreibt. Bei jedem Update ändert sich das Schema, jede Implementierung muss nachgezogen werden. Dieser Artikel zeigt, warum der direkte Weg über XML selten der klügere ist.
Was EN 16931 wirklich ist
Die meisten Entwickler begegnen EN 16931 zum ersten Mal, wenn das Finanzamt oder ein Großkunde plötzlich „eine konforme XRechnung" verlangt. Was dahintersteckt: ein europäischer CEN-Standard, der exakt definiert, welche Felder eine E-Rechnung enthalten muss, welche Datentypen gelten und wie die semantischen Regeln zu validieren sind. Deutschland implementiert diesen Standard als XRechnung (reines XML) und als ZUGFeRD (PDF + eingebettetes XML).
| Eigenschaft | Direktes XML | JSON via API |
|---|---|---|
| Erstellung | Manuell mit 3 Namespaces | Einfache JSON-Felder |
| Syntax | UBL 2.1 / UN/CEFACT CII | Abstrahiert durch API |
| Validierung | Separater CLI-Schritt (xsltproc) | Automatisch bei jedem Request |
| Schema-Updates | Eigene Codepflege bei EN-16931-Revision | Update transparent durch API |
| Fehlerausgabe | Rohe XSD-Fehlermeldung | Lesbare, feldgenaue Fehlermeldung |
| Einstiegshürde | Hoch — Tage bis erste valide Rechnung | Niedrig — Minuten bis erste Rechnung |
XML-Direkt vs. JSON via API — der ehrliche Vergleich
Schlüsselprobleme (XML-DIY)
- ✕Pflege von 3 XML-Namespaces + Namespace-Mapping bei jedem Standard-Update
- ✕Schemavalidierung fehlt → Fehler erst zur Laufzeit oder beim Einreichen
- ✕Fehlersuche auf der Kommandozeile (xsltproc, xmllint) — kein Entwickler-Feedback
- ✕Jede Profiländerung (z. B. XRechnung 3.0 → 4.0) erfordert komplettes Rebuild
- ✕Kein Playground — jeder Test kostet Debug-Zeit in der eigenen Umgebung
Voraussetzungen (JSON-API-Modell)
- ✓Felder nach EN-16931-Semantik — kein XML-Wissen nötig
- ✓Schemavalidierung bei jeder Anfrage automatisch
- ✓Feldgenaue Fehlermeldungen im HTTP-Response — sofort actionable
- ✓Standard-Fehlerbehandlung über HTTP-Statuscodes
- ✓Playground zum Testen direkt in den Docs — keine lokale Umgebung nötig
Kosten: Wie sieht das im Code aus?
Konkrete Zahlen: Wieviel Code schreibt ein Entwickler, bevor die erste valide Rechnung rauskommt?
Option A — XML direkt, vereinfacht, ohne Schema-Fixes:
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_3.0</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>2024-001</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20241215</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<!-- SupplyChainTradeTransaction mit Seller, Buyer, Positionen ... -->
<!-- ~200 weitere Zeilen XML-Boilerplate -->
</rsm:CrossIndustryInvoice>↑ Und das ist noch die vereinfachte Version. Ohne Schemavalidierung, ohne Fehlerbehandlung, ohne Profil-Management. Eine realistische Implementierung kommt auf 400–600 Zeilen XML-Generierungscode.
Option B — JSON-Request an die API (aus der Praxis):
POST /api/v1/zugferd/createXinvoiceFromJson
Authorization: Bearer <API_KEY>
Content-Type: application/json
{
"invoice": {
"invoiceNumber": "2024-001",
"invoiceIssueDate": "2024-12-15",
"invoiceTypeCode": "380",
"invoiceCurrencyCode": "EUR",
"buyerReference": "04011000-12345-06",
"seller": {
"sellerName": "Muster GmbH",
"sellerVatIdentifier": "DE123456789",
"sellerElectronicAddress": "info@muster.de",
"sellerPostalAddress": {
"sellerCity": "Berlin",
"sellerPostCode": "10115",
"sellerCountryCode": "DE"
}
},
"buyer": {
"buyerName": "Kunde AG",
"buyerPostalAddress": {
"buyerCity": "München",
"buyerPostCode": "80331",
"buyerCountryCode": "DE"
}
},
"documentTotals": {
"sumOfInvoiceLineNetAmount": 2400.00,
"invoiceTotalAmountWithoutVat": 2400.00,
"invoiceTotalVatAmount": 456.00,
"invoiceTotalAmountWithVat": 2856.00,
"amountDueForPayment": 2856.00
},
"vatBreakdown": [
{
"vatCategoryTaxableAmount": 2400.00,
"vatCategoryTaxAmount": 456.00,
"vatCategoryCode": "S",
"vatCategoryRate": 19.00
}
],
"invoiceLine": [
{
"invoiceLineIdentifier": "1",
"invoicedQuantity": 20,
"invoicedQuantityUnitOfMeasureCode": "HUR",
"invoiceLineNetAmount": 2400.00,
"priceDetails": { "itemNetPrice": 120.00 },
"lineVatInformation": [
{ "invoicedItemVatCategoryCode": "S", "invoicedItemVatRate": 19.00 }
],
"itemInformation": { "itemName": "Softwareentwicklung Q4 2024" }
}
]
}
}Die API-Antwort — direkt nutzbar:
HTTP/1.1 200 OK
Content-Type: application/json
{
"valid": true,
"message": "XInvoice created successfully",
"numberOfXInvoiceErrors": 0,
"xInvoice": "<base64-encoded XRechnung XML>",
"xInvoiceErrors": []
}ZUGFeRD-ähnliche JSON-Struktur, andere Endpoints
Das ZUGFeRD-Format folgt derselben JSON-Struktur — nur der Endpoint ändert sich. Zusätzlich kann ein bestehendes PDF als Basis übergeben werden, das die API als visuellen Layer nutzt:
POST /api/v1/zugferd/createZugferdFromJson
{
"invoice": { /* identische Struktur wie createXinvoiceFromJson */ },
"invoicePdf64": "<optional: bestehendes PDF als Base64>"
}
// Antwort: { "zugferd": "<base64 PDF/A-3>", "zugferdValid": true, ... }
// PDF mit eingebettetem XML — GoBD-konform,
// valide nach EN 16931 + ZUGFeRD 2.3 / Factur-X 1.0Das EN 16931-Update-Problem
EN 16931 ist kein statischer Standard. Die Schematron-Regeln werden aktualisiert, neue XRechnung-Versionen kommen raus, ZUGFeRD zieht nach. Wer direkt gegen XML baut, trägt diese Last selbst.
| Datum / Version | Direktes XML | JSON mit rechnungsapi.de |
|---|---|---|
| Nov 2017 — EN 16931:2017 | Initiale Implementierung nötig | Keine Aktion nötig |
| Jan 2019 — XRechnung 1.2 | Namespace-Update, Schematron-Austausch | Keine Aktion nötig |
| Okt 2021 — XRechnung 2.0 | Pflichtfelder geändert → Code-Anpassung | Keine Aktion nötig |
| Jul 2023 — XRechnung 3.0 | CII-Profil-Umbau, neuer guideline-URI | Keine Aktion nötig |
| 2026 — EN 16931:2026 | Kompletter Schema-Review fällig | Update transparent durch API |
| Aug 2026 — XRechnung 4.0 | Peppol-Alignment, weitere Änderungen | Keine Aktion nötig |
Aktuell relevant: XRechnung 4.0 ab 01.08.2026
Die Peppol-Deadline zwingt alle Direktimplementierungen zum Update. Wer über die API arbeitet, ist automatisch kompatibel.
Was Schemavalidierung bedeutet — und warum die Fehlerbehandlung der API Gold wert ist
Eine XRechnung hat zwei Validierungsebenen: die syntaktische (XSD-Schema) und die semantische (Schematron-Regeln). Wer direkt XML baut, muss beide selbst implementieren — oder hofft, dass der Empfänger erst beim Einreichen auf Fehler hinweist.
Die API validiert beide Ebenen bei jedem Request. Eine fehlerhafte Rechnung liefert sofort einen 400 Bad Request mit exakt dem Feld und der Regel, die verletzt wurde:
// Fehlerbeispiel: fehlende Buyer Reference (Leitweg-ID) beim B2G-Empfänger
HTTP/1.1 200 OK
Content-Type: application/json
{
"valid": false,
"message": "XInvoice validation failed",
"numberOfXInvoiceErrors": 1,
"xInvoice": null,
"xInvoiceErrors": [
{
"id": "BR-DE-15",
"line": null,
"location": "/rsm:CrossIndustryInvoice/rsm:ExchangedDocument",
"message": "Das Element 'Buyer reference' (BT-10) ist ein Pflichtfeld.",
"schemaFile": "XRechnung-CII-validation.xsl",
"type": "error"
}
]
}Im Vergleich dazu: Eine rohe XSD-Fehlermeldung aus einem Kommandozeilen-Validator zeigt den XML-Pfad und den Schematron-Regelnamen — aber nicht, welches Ihrer JSON/DB-Felder das Problem verursacht hat. Die Übersetzung kostet Zeit.
Wann direktes XML Sinn macht
Faire Antwort: Es gibt Fälle, in denen der direkte XML-Weg der richtige ist.
- Sie bauen ein ERP-System, das EN 16931 als Core-Kompetenz intern beherrschen muss — z. B. SAP-Modul-Entwicklung.
- Ihr System verarbeitet bereits Millionen von Rechnungen und Sie haben ein dediziertes Team für XML-Compliance.
- Sie integrieren in eine Peppol-Infrastruktur, die direkt AS4-Nachrichtenprotokolle und CII-XML verlangt.
- Regulatorische Anforderungen schreiben vor, dass kein externer Dienst in den Generierungsprozess eingebunden sein darf.
Für alle anderen — und das ist die große Mehrheit der Entwickler, die eine App, ein Buchhaltungssystem oder eine SaaS-Plattform bauen — ist der API-Ansatz der ökonomisch und technisch vernünftigere Weg.
Fazit
Direktes XML-Editing ist kein Zeichen technischer Kompetenz — es ist technische Schuld, die bei jedem Standard-Update fällig wird. Ein JSON-API-Modell abstrahiert genau das Komplexe (Namespaces, Schematron, Profilversionierung) und lässt Entwickler das tun, was ihr eigentliches Produkt ausmacht. Die E-Rechnungspflicht ist nicht das Problem — die Zeit, die in XML-Maintenance fließt, ist es.
Erste valide XRechnung in unter 10 Minuten
Kein XML-Setup, keine Namespace-Dokumentation. POST-Request senden, valide Rechnung zurückbekommen — sofort im Playground testbar.