XRechnung 3.0.2 Conformance
May 7, 2026100% KoSIT conformance: all 86 official reference messages validate green. Plus XRechnung Extension, construction-sector tax (§13b/§48 EStG), a cross-country helper rollout, and 8 new request fields + 3 new endpoints in the REST API.
100% KoSIT conformance
All 86 official KoSIT reference messages validate green against Schematron 3.0.2.
XRechnung Extension
Sub-invoice lines (BG-DEX-01) and third-party payments (BG-DEX-09) — switch via profile: xrechnung-extension.
Construction: §13b / §48
Reverse charge §13b UStG (norm-supported) and §48 EStG construction withholding via structured note.
REST API schema sync
8 new optional fields and 3 new endpoints, all documented in /openapi-1-3.json.
Full KoSIT Conformance
Previously: ~70% norm-conformant — some BTs were in the interface but not in the XML. Now: all 86 official KoSIT reference messages from the xrechnung-testsuite repository validate green via xmllint-wasm + Schematron 3.0.2 in the test suite.
A corpus-driven round-trip test parses → regenerates → re-parses each fixture and compares the canonical shape (type, invoice number, currency, item count, tax rates, line totals, seller/buyer presence, sub-item depth, third-party payment count).
XRechnung Extension
Activated via invoice.profile = "xrechnung-extension". The CustomizationID switches to the extension URN and the following structures become available:
Sub-Invoice-Lines (BG-DEX-01)
items[].subItems[] renders as nested cac:SubInvoiceLine inside the parent cac:InvoiceLine in UBL. Arbitrary depth (KoSIT corpus uses 2-3 levels). Each sub-line has exactly one cac:ClassifiedTaxCategory (BR-DEX-03). Sum check BR-DEX-02 (Σ child BT-131 = parent BT-131) is enforced by Schematron.
Third-Party Payments (BG-DEX-09)
thirdPartyPayments[] with type, paidAmount, description emits as cac:PrepaidPayment with ID + PaidAmount + InstructionID. Satisfies BR-DEX-10..14 (required field combinations, max 2 decimals, currency = BT-5).
Example: Extension request with sub-items + third-party payment
1{2 "invoice": {3 "invoiceNumber": "BAU-2026-042",4 "type": "invoice",5 "issueDate": "2026-05-07",6 "currency": "EUR",7 "profile": "xrechnung-extension",8 "serviceCategory": "construction",9 "constructionTax": {10 "exemptionCertificateNumber": "FNR-2026-12345",11 "recipientTaxOffice": "Finanzamt Berlin Nord"12 },13 "seller": { "name": "Bau Acme GmbH", "countryCode": "DE", "vatId": "DE123456789" },14 "buyer": { "name": "Großbau AG", "countryCode": "DE", "vatId": "DE987654321" },15 "items": [16 {17 "position": 1,18 "description": "Bauabschnitt A — Rohbau",19 "quantity": 1,20 "unitPrice": 50000.00,21 "taxRate": 19,22 "subItems": [23 { "type": "DETAIL", "description": "Fundament", "netAmount": 20000.00 },24 { "type": "DETAIL", "description": "Mauerwerk", "netAmount": 30000.00 }25 ]26 }27 ],28 "thirdPartyPayments": [29 { "type": "advance", "paidAmount": 10000.00, "description": "Bauherren-Vorauszahlung" }30 ],31 "subtotal": 50000.00,32 "total": 59500.0033 }34}Construction Sector: §13b + §48 EStG
Reverse charge (norm-supported)
Set serviceCategory: "construction" and use the AE tax category. The standard note „Steuerschuldnerschaft des Leistungsempfängers gemäß §13b UStG“ is emitted in both UBL and CII.
Construction withholding (norm gap)
XRechnung has no field for exemption certificate or 15% withholding. Solution: structured note in BT-22 following the KoSIT #SKONTO# convention. Use constructionTax with exemptionCertificateNumber / withholdingPercent / recipientTaxOffice — emitted as #FREISTELLUNG#NR=...#PROZENT=15.00#FA=...# note in both UBL and CII.
Cross-Country Helper Rollout
Three reusable helpers close structural gaps across multiple countries at once. Previously: only DE had them. Now rolled out to 12 countries:
- BG-24Attachments (BT-122..125) — embedded documents in UBL and CII, 200 MiB cap per attachment (KoSIT-aligned). Rolled out to DE, BE, NL, PT, FR.
- BR-CL-01UBL CreditNote Root Switch — TypeCode 381 lives under ubl:CreditNote root (not ubl:Invoice). Rolled out to DE, BE, NL, PT.
- BG-20/21Document-Level Allowance/Charge — BT-95/96 + BT-102/103 with ReasonCode and TaxCategory. Rolled out to DE, BE, NL, PT, FR.
Additionally: new GR myDATA structural validator (lib-invoice-validator-gr) and a CH ZUGFeRD wrapper (DE CII generator with CHF + CHE VAT-ID propagation), enabling EN-16931-conformant XML next to the QR-Bill PDF.
REST API: 8 New Fields + 3 New Endpoints
The OpenAPI/Zod schema was two sprints out of sync with the invoice-backend interface. Now everything is explicitly typed, documented, and example-payloaded. All fields are optional and .passthrough() is preserved — no breaking changes for existing clients.
New Optional Fields in invoiceSchema
profile— xrechnung | xrechnung-extension — switches Extension mode onitems[].subItems— Recursive sub-invoice lines (BG-DEX-01), arbitrary depththirdPartyPayments— Third-party payments (BG-DEX-09)attachments— Embedded documents (BG-24, BT-122..125)referencedInvoiceNumber + Date— Predecessor invoice (BG-3, BT-25/26) for credit notesdeliveryNote— Delivery note reference (BT-16/17)serviceCategory— construction | general — enables §13b reverse charge behaviorconstructionTax— §48 EStG construction withholding (exemption cert, withholding percent, tax office)
New Endpoints
/api/v1/invoice/es/verifactu-qr
Spanish VeriFactu QR code per Real Decreto 1007/2023 Annex II — URL, PNG, SVG.
/api/v1/invoice/ch/zugferd/generate
CH wraps the DE CII generator with CHF + CHE-VAT-ID. Use case: CH supplier invoicing DE/AT recipients needs EN-16931-conformant XML next to the QR-Bill PDF.
validationErrorSchema.code
Tightened from free string to a discriminated union of 50+ explicit DE_* / GR_* codes plus a fallback string for dynamic Schematron rule IDs.
Example: VeriFactu QR request
1POST /api/v1/invoice/es/verifactu-qr2 3{4 "sellerNif": "B12345674",5 "invoiceSeries": "2026/A",6 "invoiceNumber": "0001",7 "invoiceDate": "07-05-2026",8 "total": 1234.56,9 "verifactuMode": false10}11 12# Response13{14 "url": "https://prewww2.aeat.es/wlpl/TIKE-CONT/ValidarQR?nif=B12345674&numserie=2026%2FA-0001&fecha=07-05-2026&importe=1234.56",15 "png": "<base64 PNG>",16 "svg": "<svg ...>"17}