← E-invoicing guides

XRechnung & ZUGFeRD for Developers: EN 16931 Without the Pain

As of: 01.09.2026

You've been asked to "just add XRechnung export." Here's the mental model that saves you a week of spec reading — and the traps that make validators reject your files.

The layer cake

  1. EN 16931 — the semantic model: ~160 business terms (BT-1 invoice number, BT-10 buyer reference, BG-23 VAT breakdown…). Format-agnostic.
  2. Syntax — two XML bindings exist: UN/CEFACT CII and UBL. Germany accepts both; ZUGFeRD always uses CII. Pick CII if you want one syntax for both formats.
  3. CIUS — country profiles that tighten the base standard. XRechnung is Germany's CIUS: it upgrades optional fields to mandatory (buyer reference, seller contact, payment details) via the BR-DE rule set.
  4. Packaging — XRechnung ships as bare XML; ZUGFeRD/Factur-X embeds the same CII XML into a PDF/A-3 attachment with XMP metadata.

Validation is two different things

Layer Checks Tooling
XSD schema structure: elements, order, types any XML library
Schematron business rules: sums, code lists, BR-DE-* the official KoSIT validator (Java)

Passing XSD means little — most real-world rejections are Schematron rule violations. Wire the KoSIT validator into CI; treat it as the reference implementation of "valid."

The mistakes everyone makes once

Don't hand-roll the XML

Mature open-source libraries exist and are battle-tested against KoSIT:

Build your invoice as a plain data object, map it to the library's builder, validate with XSD locally and KoSIT in CI. Total: a few hundred lines instead of a few thousand.

Or skip the integration entirely

If you just need compliant files (or an API later) without owning the mapping: NurRechnung generates XRechnung 3.x and ZUGFeRD from one data set, validated against the official rules — free validator and viewer included for debugging your own output.


Format engineering guide — not tax advice.