Warum XRechnung implementieren — und wer muss ab wann?
Empfangen müssen deutsche Unternehmen E-Rechnungen bereits seit dem 1. Januar 2025. Beim Versand läuft die Übergangsregelung des § 27 Abs. 38 UStG gestaffelt aus: Ab dem 1. Januar 2027 entfällt sie für Unternehmen mit mehr als 800.000 Euro Gesamtumsatz im Vorjahr, ab dem 1. Januar 2028 für alle übrigen. Maßgeblich ist der Umsatz des Rechnungsstellers, nicht des Empfängers. Details zu den Fristen klärt XRechnung-Pflicht 2027.
XRechnung ist der deutsche Standard nach EN 16931 — und das Pflichtformat für Rechnungen an öffentliche Auftraggeber. Wer Software für Rechnungsstellung entwickelt, kommt an XRechnung nicht vorbei.
Dieser Artikel zeigt Ihnen als Entwickler den direkten Weg: XML-Struktur verstehen, Pflichtfelder korrekt befüllen, gegen EN 16931 validieren und per API automatisieren. Stand: Juli 2026, geprüft gegen die gültige Spezifikation XRechnung 3.0.2. Den organisatorischen Rahmen zeigt der Leitfaden dazu, wie Steuerberater ihre Mandanten auf die E-Rechnung umstellen.
1. UBL oder CII: Welche XML-Syntax soll ich wählen?
XRechnung unterstützt zwei XML-Syntaxen. Beide sind gleichwertig gültig — die Wahl hängt von Ihrem Anwendungsfall ab.
UBL 2.1 (Universal Business Language)
UBL ist der international verbreitetere Standard. Die Rechnungsdaten liegen im Namespace urn:oasis:names:specification:ubl:schema:xsd:Invoice-2. Das Root-Element ist <Invoice>.
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>
<cbc:ID>RE-2026-001</cbc:ID>
<cbc:IssueDate>2026-03-22</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cac:AccountingSupplierParty>
<!-- Rechnungssteller -->
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<!-- Rechnungsempfänger -->
</cac:AccountingCustomerParty>
<cac:LegalMonetaryTotal>
<!-- Summen -->
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<!-- Rechnungspositionen -->
</cac:InvoiceLine>
</Invoice>UN/CEFACT CII (Cross-Industry Invoice)
CII ist die UN-Syntax, die auch ZUGFeRD verwendet. Das Root-Element ist <CrossIndustryInvoice>. Die Daten sind hierarchisch in Trade-Blöcke gegliedert.
<?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:xeinkauf.de:kosit:xrechnung_3.0</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>RE-2026-001</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20260322</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<!-- Handelspartner, Lieferung, Zahlung -->
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>UBL oder CII?
UBL eignet sich, wenn Sie international agieren oder PEPPOL nutzen. CII ist die Wahl, wenn Sie auch ZUGFeRD unterstützen wollen — ZUGFeRD verwendet ausschließlich CII.
2. Welche Pflichtfelder braucht eine XRechnung?
EN 16931 definiert rund 160 semantische Datenfelder (BT) in gut 30 Gruppen (BG). Nicht alle sind Pflicht. Die folgende Tabelle zeigt die Mindestanforderungen für eine gültige XRechnung:
| BT-Nr. | Feld | Beschreibung | Beispielwert |
|---|---|---|---|
| BT-1 | Rechnungsnummer | Eindeutige Kennung der Rechnung | RE-2026-001 |
| BT-2 | Rechnungsdatum | Ausstellungsdatum | 2026-03-22 |
| BT-3 | Rechnungsart | UNTDID 1001 Code | 380 (Rechnung) |
| BT-5 | Währung | ISO 4217 Währungscode | EUR |
| BT-27 | Verkäufername | Name des Rechnungsstellers | Muster GmbH |
| BT-44 | Käufername | Name des Rechnungsempfängers | Kunde AG |
| BT-109 | Rechnungsbetrag ohne MwSt. | Gesamtbetrag exkl. MwSt. | 1000.00 |
| BT-110 | MwSt.-Betrag | Summe der Umsatzsteuer | 190.00 |
| BT-112 | Rechnungsbetrag mit MwSt. | Gesamtbetrag inkl. MwSt. | 1190.00 |
| BT-115 | Fälliger Betrag | Zu zahlender Betrag | 1190.00 |
Welche Felder verlangt XRechnung zusätzlich (BR-DE)?
Die deutschen Geschäftsregeln (BR-DE) verschärfen EN 16931. Die wichtigsten:
- Buyer reference (BT-10): BR-DE-15 macht dieses Feld in jeder XRechnung zur Pflicht — auch im B2B.
- Zahlungsdaten (BG-16): BR-DE-1 verlangt Angaben zu „PAYMENT INSTRUCTIONS", etwa die IBAN des Verkäufers bei Überweisung.
- E-Mail-Adresse (BT-43): BR-DE-7 verlangt die Kontakt-E-Mail des Verkäufers.
- Zahlungsbedingungen (BT-20): Freitext für Zahlungskonditionen.
Leitweg-ID: nur bei Behörden, nicht im B2B
Hier verwechseln viele Implementierungen zwei Dinge. BT-10 ist ein generisches Käufer-Referenzfeld. Die Leitweg-ID ist kein eigenes Feld, sondern ein Inhalt, den Bund, Länder und Kommunen in BT-10 erwarten (B2G und G2G). Format: 04011000-12345-67.
Im B2B gibt es in der Regel keine Leitweg-ID. BT-10 bleibt trotzdem Pflicht — dort steht dann die Referenz, die Ihr Kunde vorgibt, etwa eine Bestellnummer. Einzelne Länder und Kommunen geben abweichende Zuordnungsmuster vor; auch die gehören in BT-10.
3. Wie erzeuge ich eine XRechnung per API?
Statt XML manuell zu bauen, können Sie die E-Invoice API nutzen. Sie senden Rechnungsdaten als JSON — die API erzeugt valides XRechnung-XML.
API starten (Docker)
docker run -p 8000:8000 ghcr.io/jenslaufer/e-invoice:latestXRechnung generieren (Python)
Dieses Beispiel erstellt eine vollständige XRechnung im UBL-Format:
import requests
invoice_data = {
"invoice_number": "RE-2026-001",
"issue_date": "2026-03-22",
"due_date": "2026-04-21",
"currency_code": "EUR",
"invoice_type_code": "380",
"buyer_reference": "04011000-12345-67", # Leitweg-ID
"seller": {
"name": "Muster GmbH",
"street": "Musterstraße 1",
"city": "Berlin",
"postal_code": "10115",
"country_code": "DE",
"tax_id": "DE123456789",
"contact": {
"email": "rechnung@muster.de"
},
"bank_account": {
"iban": "DE89370400440532013000"
}
},
"buyer": {
"name": "Bundesministerium für Beispiele",
"street": "Regierungsstraße 10",
"city": "Berlin",
"postal_code": "10117",
"country_code": "DE"
},
"lines": [
{
"description": "Softwareentwicklung",
"quantity": 10,
"unit_code": "HUR",
"unit_price": 100.00,
"tax_category": "S",
"tax_percent": 19.0
}
],
"payment_terms": "Zahlbar innerhalb von 30 Tagen"
}
# XRechnung als UBL generieren
response = requests.post(
"http://localhost:8000/api/v1/invoices/xml",
json=invoice_data,
params={"syntax": "ubl"}
)
if response.status_code == 200:
with open("rechnung.xml", "wb") as f:
f.write(response.content)
print("XRechnung erstellt: rechnung.xml")
else:
print(f"Fehler: {response.json()}")CII-Syntax verwenden
Für CII-Output ändern Sie nur den Parameter:
response = requests.post(
"http://localhost:8000/api/v1/invoices/xml",
json=invoice_data,
params={"syntax": "cii"}
)4. Wie validiere ich eine XRechnung gegen EN 16931?
Eine XRechnung muss fünf Validierungsschichten bestehen. Referenz ist der KoSIT-Validator mit der offiziellen Validator-Konfiguration — was der ablehnt, lehnt auch der Empfänger ab. Jede Schicht prüft unterschiedliche Aspekte:
| Schicht | Prüfung | Werkzeug |
|---|---|---|
| 1. Schema | XML-Struktur und Datentypen | XSD-Validierung |
| 2. EN 16931 | Europäische Geschäftsregeln (BR-*) | Schematron |
| 3. XRechnung CIUS | Deutsche Geschäftsregeln (BR-DE-*) | Schematron |
| 4. Berechnung | Summen, Steuern, Rundung | Arithmetische Prüfung |
| 5. Semantik | Codelisten, Referenzen, Konsistenz | Geschäftslogik |
Validierung per API
# XRechnung validieren
with open("rechnung.xml", "rb") as f:
xml_content = f.read()
response = requests.post(
"http://localhost:8000/api/v1/invoices/validate",
files={"file": ("rechnung.xml", xml_content, "application/xml")}
)
result = response.json()
print(f"Gültig: {result['valid']}")
if not result["valid"]:
for error in result["errors"]:
print(f" [{error['rule']}] {error['message']}")Eine typische Validierungsantwort bei Fehlern:
{
"valid": false,
"errors": [
{
"rule": "BR-DE-15",
"message": "Das Element \"Buyer reference\" (BT-10) muss übermittelt werden.",
"severity": "error",
"location": "/Invoice"
}
],
"warnings": []
}Validierung in die CI/CD-Pipeline integrieren
Validieren Sie generierte Rechnungen automatisch in Ihrer Pipeline:
# validate_invoices.py
import sys
import requests
import glob
api_url = "http://localhost:8000/api/v1/invoices/validate"
errors_found = False
for xml_file in glob.glob("output/*.xml"):
with open(xml_file, "rb") as f:
resp = requests.post(
api_url,
files={"file": (xml_file, f, "application/xml")}
)
result = resp.json()
if not result["valid"]:
errors_found = True
print(f"FEHLER in {xml_file}:")
for err in result["errors"]:
print(f" [{err['rule']}] {err['message']}")
else:
print(f"OK: {xml_file}")
sys.exit(1 if errors_found else 0)5. Welche Fehler treten am häufigsten auf?
Diese Fehler treten bei der EN 16931 Implementierung am häufigsten auf. Welche Fehler im laufenden Betrieb zu Ablehnungen führen, zeigt Die häufigsten Fehler bei der E-Rechnung.
Fehler 1: Falsche CustomizationID
Die CustomizationID muss exakt stimmen. Die Regel BR-DE-21 prüft den Wert zeichengenau — eine Abweichung führt zur Ablehnung.
Zwei Stolperfallen: Seit XRechnung 3.0 lautet der Namensraum xeinkauf.de:kosit:xrechnung_. Ältere Anleitungen zeigen noch die 2.x-Form xoev-de:kosit:standard:xrechnung_ — die ist für 3.x ungültig. Und der Wert trägt nur Major- und Minor-Version: Auch bei Spezifikation 3.0.2 steht dort _3.0, nicht _3.0.2.
<!-- Falsch: ohne CIUS-Kennung -->
<cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
<!-- Falsch: 2.x-Namensraum in einer 3.x-Rechnung -->
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_3.0</cbc:CustomizationID>
<!-- Richtig (XRechnung 3.0.2) -->
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>In CII steht derselbe String in rsm:ExchangedDocumentContext/ram:GuidelineSpecifiedDocumentContextParameter/ram:ID. Semantisch ist es BT-24 (Specification identifier).
Fehler 2: Steuerberechnung mit Rundungsfehlern
EN 16931 verlangt kaufmännische Rundung auf 2 Dezimalstellen. Fließkomma-Arithmetik führt zu Abweichungen.
# Falsch: Fließkomma-Fehler
tax = 100.05 * 0.19 # 19.0095000000000027...
# Richtig: Decimal verwenden
from decimal import Decimal, ROUND_HALF_UP
tax = (Decimal("100.05") * Decimal("0.19")).quantize(
Decimal("0.01"), rounding=ROUND_HALF_UP
) # Decimal('19.01')Fehler 3: BT-10 nur bei Behördenrechnungen befüllen
Die Geschäftsregel BR-DE-15 verlangt BT-10 (Buyer reference) in jeder XRechnung — nicht nur bei B2G. Wer das Feld im B2B wegoptimiert, weil dort keine Leitweg-ID existiert, produziert eine ungültige Rechnung. Bei öffentlichen Auftraggebern muss zusätzlich der Inhalt stimmen: eine gültige Leitweg-ID.
Fehler 4: Datumsformat in CII
CII verwendet ein anderes Datumsformat als UBL. Häufiger Fehler: ISO-8601 statt CCYYMMDD.
<!-- Falsch in CII -->
<udt:DateTimeString format="102">2026-03-22</udt:DateTimeString>
<!-- Richtig in CII -->
<udt:DateTimeString format="102">20260322</udt:DateTimeString>Fehler 5: Summen stimmen nicht überein
EN 16931 enthält arithmetische Regeln (BR-CO-*). Die Summen müssen exakt passen:
- BR-CO-10: BT-106 (Summe Nettobeträge der Positionen) = Summe aller BT-131
- BR-CO-13: BT-109 (Rechnungsbetrag ohne MwSt.) = Summe aller BT-131 − BT-107 + BT-108
- BR-CO-15: BT-112 (Rechnungsbetrag mit MwSt.) = BT-109 + BT-110 (MwSt.-Betrag)
- BR-CO-16: BT-115 (Fälliger Betrag) = BT-112 − BT-113 (bereits gezahlt) + BT-114 (Rundungsbetrag)
Zwei Details, die oft danebengehen: BT-107 und BT-108 sind bereits Summen auf Dokumentebene — die einzelnen Nachlässe stehen in BT-92, die einzelnen Zuschläge in BT-99. Und wer BT-114 in BR-CO-16 vergisst, bekommt genau dann einen Fehler, wenn gerundet wird.
Fehler 6: Falsche Unit-Codes
Mengeneinheiten stammen aus UN/ECE Recommendation 20 und Recommendation 21 — ausgewählt nach der in Rec 20, Intro 2.a) beschriebenen Methode. Codes aus Rec 21 tragen ein vorangestelltes X, etwa XPP (Packung). Wer nur in Rec 20 nachschlägt, findet die Verpackungscodes nicht. Häufige Codes:
| Code | Bedeutung |
|---|---|
HUR | Stunde |
DAY | Tag |
C62 | Stück (Einheit) |
MON | Monat |
KWH | Kilowattstunde |
TNE | Tonne (metrisch) |
Tipp: Validieren Sie jede generierte Rechnung vor dem Versand. Die E-Invoice API prüft alle 5 Schichten in einem Aufruf — Schema, EN 16931, BR-DE, Berechnung und Semantik.
6. Wie sieht eine vollständige Implementierung aus?
Das folgende Beispiel zeigt den vollständigen Workflow — Rechnung erstellen, validieren und speichern:
import requests
from pathlib import Path
API_BASE = "http://localhost:8000/api/v1"
def create_xrechnung():
"""Erstellt eine XRechnung und validiert sie."""
invoice = {
"invoice_number": "RE-2026-042",
"issue_date": "2026-03-22",
"due_date": "2026-04-21",
"currency_code": "EUR",
"invoice_type_code": "380",
"buyer_reference": "04011000-12345-67",
"seller": {
"name": "DevCorp GmbH",
"street": "Entwicklerweg 42",
"city": "München",
"postal_code": "80331",
"country_code": "DE",
"tax_id": "DE987654321",
"contact": {"email": "billing@devcorp.de"},
"bank_account": {"iban": "DE89370400440532013000"}
},
"buyer": {
"name": "Stadt München",
"street": "Marienplatz 8",
"city": "München",
"postal_code": "80331",
"country_code": "DE"
},
"lines": [
{
"description": "API-Entwicklung",
"quantity": 80,
"unit_code": "HUR",
"unit_price": 120.00,
"tax_category": "S",
"tax_percent": 19.0
},
{
"description": "Code Review",
"quantity": 20,
"unit_code": "HUR",
"unit_price": 95.00,
"tax_category": "S",
"tax_percent": 19.0
}
],
"payment_terms": "Zahlbar innerhalb von 30 Tagen netto"
}
# 1. XML generieren
resp = requests.post(
f"{API_BASE}/invoices/xml",
json=invoice,
params={"syntax": "ubl"}
)
resp.raise_for_status()
xml_bytes = resp.content
# 2. Validieren
val = requests.post(
f"{API_BASE}/invoices/validate",
files={"file": ("invoice.xml", xml_bytes, "application/xml")}
)
result = val.json()
if not result["valid"]:
for err in result["errors"]:
print(f"Fehler: [{err['rule']}] {err['message']}")
return False
# 3. Speichern
output = Path("output/RE-2026-042.xml")
output.parent.mkdir(exist_ok=True)
output.write_bytes(xml_bytes)
print(f"Valide XRechnung gespeichert: {output}")
return True
if __name__ == "__main__":
create_xrechnung()7. Was kommt als Nächstes: XRechnung 4.0, Peppol, Fristen
Sie haben die Grundlagen der XRechnung-Implementierung kennengelernt. Drei Punkte für den produktiven Einsatz:
- Beispieldatei zum Abgleich: Eine vollständige, Block für Block erklärte XRechnung zum Download — UBL und CII — finden Sie in XRechnung-Beispiel. Ideal, um Ihre eigene Ausgabe Feld für Feld dagegenzuhalten.
- Branchenerweiterungen prüfen: Bau, Gesundheit, Logistik und Automotive haben zusätzliche Anforderungen — siehe EN 16931 Branchenerweiterungen.
- ZUGFeRD parallel einrichten: Viele B2B-Empfänger bevorzugen das Hybridformat. Die Unterschiede klärt XRechnung vs. ZUGFeRD.
- Fristen beachten: Versandpflicht ab 2027 über 800.000 Euro Vorjahresumsatz, ab 2028 für alle.
Muss ich Peppol nutzen?
Nein. Der Gesetzgeber schreibt keinen Übermittlungsweg vor. Das BMF nennt E-Mail, Portal-Download, EDI, Schnittstelle oder gemeinsamen Speicherort als zulässige Wege — welchen Weg und welches zulässige Format die Parteien wählen, ist eine zivilrechtliche Frage zwischen ihnen. Für den Inlandsversand reicht XRechnung per E-Mail.
Peppol bleibt trotzdem relevant: Die KoSIT ist deutsche Peppol Authority, und XRechnung ist ab Version 3.0 inhaltlich deckungsgleich mit Peppol BIS Billing. Wer grenzüberschreitend fakturiert, kommt an einem Access Point praktisch kaum vorbei. Einordnung in Peppol im deutschen B2B.
Kommt XRechnung 4.0?
Die KoSIT bereitet XRechnung 4.0 als deutsche Umsetzung der neuen EU-Norm EN 16931-1:2026 vor; angekündigt ist ein Release Mitte bis Ende 2026, zunächst als Vorabversion ohne Produktionsfreigabe. Ein verbindliches Gültigkeitsdatum ist noch nicht veröffentlicht — die Bundle-Erstellung wartet auf die CEN-Syntaxbindings und Validierungsartefakte.
Für heutige Implementierungen ändert das nichts: Gültig ist XRechnung 3.0.2 auf Basis der EN-16931-Linie von 2017. Planen Sie die CustomizationID und die Schematron-Artefakte aber als konfigurierbar ein, nicht als Konstante im Code — mit 4.0 werden beide wechseln.
Sind Sie ab 2027 zur E-Rechnung verpflichtet?
Der kostenlose E-Rechnung-Pflichtcheck klärt Ihren Status in wenigen Minuten — unverbindlich und ohne Anmeldung.
Zum E-Rechnung-PflichtcheckOder die Checkliste direkt per E-Mail
15 Punkte mit Fristen — von der Empfangspflicht bis zur GoBD-Archivierung.
Wir respektieren Ihre Privatsphäre. Abmeldung jederzeit möglich.
Das könnte Sie auch interessieren
XRechnung-Beispiel: annotierte XML-Datei zum Download (UBL & CII)
Eine echte XRechnung 3.0 als XML-Beispieldatei zum Download — Block für Block erklärt: Kopfdaten, BuyerReference, Einheiten HUR und C62, Steuerblock, Zahlung. UBL und CII im Vergleich.
Weiterlesen E-RechnungE-Rechnung in DATEV einrichten: XRechnung & ZUGFeRD
XRechnung und ZUGFeRD in DATEV einrichten: Module, Anforderungen und GoBD-konforme Archivierung – Schritt für Schritt zur E-Rechnungspflicht ab 2027.
Weiterlesen E-RechnungEN 16931 Branchenerweiterungen: E-Rechnungen für Bau, Gesundheit und Logistik
EN 16931 allein reicht für viele Branchen nicht. So funktionieren Branchenerweiterungen für Bau, Gesundheit, Logistik und Automotive — technisch und praktisch.
Weiterlesen