Two languages for the same sentence
EN 16931 describes which details an invoice carries and what they mean — not how they are arranged in XML. For the arrangement it permits two syntaxes:
- CII (Cross Industry Invoice), from UN/CEFACT
- UBL (Universal Business Language), from OASIS
Both are complete. A document in CII and the same document in UBL contain exactly the same fields under exactly the same BT numbers. They just look nothing alike.
The same invoice number, twice
BT-1, the invoice number, in UBL:
1<ubl:Invoice xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"2 xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">3 <cbc:ID>INV-2026-0042</cbc:ID>4</ubl:Invoice>And in CII:
1<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"2 xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100">3 <rsm:ExchangedDocument>4 <ram:ID>INV-2026-0042</ram:ID>5 </rsm:ExchangedDocument>6</rsm:CrossIndustryInvoice>Same statement, same BT number, different path. That is precisely why error messages cite the BT number and not the XPath: the BT number holds in both syntaxes, the path does not.
The differences you actually notice
| CII | UBL | |
|---|---|---|
| Published by | UN/CEFACT | OASIS |
| Root element | rsm:CrossIndustryInvoice | ubl:Invoice / ubl:CreditNote |
| Typical prefixes | rsm, ram, udt | cbc, cac |
| Shape | deeply nested, three header areas | flatter, grouped by business object |
| Where you meet it | industry, hybrid formats | public procurement, Peppol |
The most visible structural difference: CII splits the document into three large
blocks — ExchangedDocument (the header), SupplyChainTradeTransaction holding
the lines, and within that agreement, delivery and settlement. UBL lays its
groups out side by side, flatter.
For a person opening an invoice for the first time, UBL is usually easier to read. For a parser the difference is meaningless.
Who demands what
This mapping is the genuinely useful part:
| Target format | Syntax | Any choice? |
|---|---|---|
| ZUGFeRD | CII | no |
| Factur-X | CII | no |
| Peppol BIS Billing 3.0 | UBL | no |
| XRechnung | CII or UBL | yes |
| FatturaPA | own syntax | — |
| Facturae | own syntax | — |
The only place with a real choice is XRechnung. And even there: if the recipient states a preference, follow it — both variants are conformant, but not every intake process is equally well prepared for both.
The XRechnung special case
XRechnung is a CIUS of EN 16931 and inherits the standard's two-track nature. It exists as a UBL file and as a CII file; both carry the same specification identifier in BT-24 and are checked by the same rule set.
In practice UBL dominates, because the German intake platforms come out of the Peppol world. With no instruction to the contrary, UBL causes fewer arguments.
What this means for implementation
The common mistake is assuming you must pick a syntax. When generating, you usually don't — you pick a target format, and it brings its syntax along. Anyone generating ZUGFeRD is generating CII without ever having made a choice.
When receiving it is the other way round. As soon as invoices arrive from several sources, both syntaxes arrive, unannounced: one supplier sends a ZUGFeRD PDF, the next a UBL XRechnung, the third a CII XRechnung. An intake process that knows only one syntax breaks on the second supplier.
💡 The practical advice: treat syntax as a detail of transport, not as part of your data model. Internally you work with BT fields; the syntax exists only at the boundary. Then switching from CII to UBL is a configuration change rather than a rebuild.