What is EN 16931? The standard under every EU e-invoice
If you're implementing e-invoicing for a European market, you'll hit the name EN 16931 before anything else. It's not a file format you can open — it's the semantic rulebook that every EU e-invoice format is built on, or at least measured against.
What EN 16931 actually is
EN 16931 is a European standard (published by CEN, the European
Committee for Standardization) that defines a semantic data model
for invoices: a list of roughly 150 business terms (seller name,
VAT identifier, invoice line net amount, and so on — each with a stable
code like BT-1 for the invoice number or BT-10
for the buyer reference) and a set of business rules that say how
those terms must relate to each other (each with a code like
BR-CO-15, "the invoice total amount must equal the sum of
the invoice line net amounts, minus allowances, plus charges").
Crucially, EN 16931 does not say what the XML has to look like. It says what the invoice has to mean. That separation is why the same semantic content can be serialized in more than one XML syntax — which is exactly what happens in practice.
Two syntaxes, one model
The standard officially supports two XML syntaxes:
- UBL 2.1 (OASIS Universal Business Language) — readable element
names like
cbc:IDandcac:AccountingSupplierParty. This is what Peppol BIS 3.0 uses exclusively. - UN/CEFACT CII D16B (Cross Industry Invoice) — a more code-driven syntax with EDI roots. This is the XML packed inside Factur-X and ZUGFeRD hybrid PDFs.
Because both syntaxes carry the same underlying business terms, a
compliant invoice can usually be converted between them without losing
information — that's what our own /v1/convert/ubl-to-cii and
/v1/convert/cii-to-ubl endpoints do, and why they can afford
to be lossless-or-rejected: if a document uses something the shared
EN 16931 subset can't carry (document-level allowances/charges, prepaid
amounts, attachments), conversion fails loudly with a
422 unsupported_features instead of quietly dropping data.
CIUS: national and sector flavors on top
EN 16931 leaves some room deliberately open — optional fields, a few places where a country can be stricter than the baseline. A CIUS (Core Invoice Usage Specification) is a formal restriction of EN 16931 for a specific context. The ones you'll run into most:
- Peppol BIS 3.0 — the four-corner network's own CIUS, UBL only.
- XRechnung — Germany's CIUS, UBL or CII, with extra mandatory fields for public-sector invoicing (see our Leitweg-ID article).
- RO_CIUS — Romania's CIUS for its e-Factura system.
None of these invent new business terms. They restrict which of the
existing EN 16931 fields are mandatory, and sometimes add rules of their
own (that's why German XRechnung errors carry a BR-DE-* code
and French ones carry BR-FR-* — same rule family, different
national layer).
Not every EU invoice format is EN 16931. Italy's FatturaPA, Spain's Facturae and Poland's KSeF / FA_VAT are separate, older national XML vocabularies that cover domestic B2B/B2C invoicing outside the EN 16931 family — they existed before, or run in parallel to, the EU-wide EN 16931 push. See our formats hub for the full split between the pan-EU core and these national terminal formats.
Validating against it
In practice you rarely validate "against EN 16931" alone — you validate
against a profile (plain EN 16931, Peppol, XRechnung, the French
fr profile, RO). Every finding in the response carries the
exact rule id, so you know which of the ~250 official rules failed and
why:
curl -X POST "$BASE/v1/validate/ubl?profile=en16931" \ -H "Content-Type: application/xml" --data-binary @invoice.xml
{
"valid": false,
"profile": "en16931",
"counts": {"fatal": 1, "warning": 0},
"findings": [
{"severity": "fatal", "rule_id": "BR-CO-15",
"message": "Invoice total amount without VAT (BT-109) must equal ..."}
]
}
Every BR-* and PEPPOL-* code we return links
to a plain-language explanation with a fix — browse the full
error code reference, or start with the
official model itself in our UBL /
Peppol landing page.
Keep reading
Want to try this against a real invoice?
Every example above calls the same API you can call today — validate for free, or read the full reference.