EN 16931, UBL & PEPPOL
Three standards stack to make one interoperable invoice: EN 16931 says what an invoice means, UBL 2.1 says how to write it in XML, and PEPPOL BIS 3.0 says how parties agree to exchange it. Here's what each does, in plain language.
Why standards at all
A tax authority — or a buyer's accounting system — can't process a PDF or a bespoke JSON shape automatically. Electronic invoicing mandates require a structured, machine-readable invoice in an agreed format, so the data can be validated and posted without a human re-keying it. The three standards below are the ones the European and PEPPOL-aligned world has settled on. TaxLens produces all three from a single booking.
EN 16931 — the meaning
The European standard for the semantic content of an invoice. It is format-agnostic: it defines the information, not the file.
EN 16931 breaks an invoice into named Business Terms — each a single piece of information with a stable identifier:
BT-1— invoice number;BT-2— issue date;BT-5— currencyBT-27— seller name;BT-31— seller VAT identifier;BT-40— seller countryBT-44— buyer name;BT-55— buyer countryBG-23— VAT breakdown group;BT-118/119/116/117— each VAT subtotal's category, rate, base, and tax
It also carries Business Rules (BR-*) that an invoice must satisfy — for example, every VAT line must reconcile against a matching VAT subtotal. The TaxLens GET …/document response is exactly this model in JSON. The pre-check enforces the mandatory subset; see Send-readiness.
UBL 2.1 — the syntax
Universal Business Language: the XML vocabulary that binds each EN 16931 Business Term to concrete XML elements.
EN 16931 says "there is a seller VAT identifier (BT-31)." UBL 2.1 says where that goes in the XML tree (cac:AccountingSupplierParty → cac:PartyTaxScheme → cbc:CompanyID). TaxLens serializes to UBL with a dependency-free serializer, so the file is structurally correct by construction; XSD-conformance is verified in our test suite, not validated at request time. The runtime gate is the EN 16931 / PEPPOL mandatory pre-check — see Send-readiness.
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents">
<!-- PEPPOL BIS 3.0 profile: this is the "exchange agreement" layer -->
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>A-2026-000145</cbc:ID> <!-- BT-1 invoice number -->
<cbc:IssueDate>2026-06-06</cbc:IssueDate> <!-- BT-2 issue date -->
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode> <!-- 380 = commercial invoice -->
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode> <!-- BT-5 -->
<cac:AccountingSupplierParty>
<cac:Party>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Hotel Adler GmbH</cbc:RegistrationName> <!-- BT-27 seller name -->
</cac:PartyLegalEntity>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE123456789</cbc:CompanyID> <!-- BT-31 seller VAT id -->
<cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
</cac:PartyTaxScheme>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:TaxTotal>
<cac:TaxSubtotal> <!-- BG-23 one VAT subtotal per (category, rate) -->
<cbc:TaxableAmount currencyID="EUR">600.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">60.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID> <!-- S = standard-rated -->
<cbc:Percent>10</cbc:Percent> <!-- BT-119 the VAT rate -->
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
</Invoice>PEPPOL BIS 3.0 — the exchange agreement
PEPPOL BIS Billing 3.0 is a profile on top of EN 16931 + UBL: it picks a subset of fields, adds a few extra rules trading partners need, and stamps the document with a CustomizationID so a receiver instantly knows which rulebook applies. The CustomizationID you saw above is what tells a PEPPOL Access Point "this is a PEPPOL BIS 3.0 invoice — validate it against that profile."
In one sentence each
- EN 16931 — the agreed meaning of every field on an invoice.
- UBL 2.1 — how to write those fields as XML.
- PEPPOL BIS 3.0 — the profile two parties agree to exchange.
Next: make sure your document actually satisfies these rules in Send-readiness & fixing violations, or see why occupancy tax is left off in VAT-only invoices.