How to Generate a Valid UBL E-Invoice (EN 16931 / BIS 3.0)

To generate a valid e-invoice programmatically you produce a UBL 2.1 XML document whose content satisfies the European standard EN 16931, profiled as Peppol BIS Billing 3.0. The three names confuse everyone once: UBL is the XML vocabulary (element names and structure), EN 16931 is the semantic standard (which business terms an invoice must carry), and BIS 3.0 is a conformant restriction of EN 16931 expressed in UBL, plus Peppol’s own network rules. A BIS invoice declares what it is through two elements (`CustomizationID` (the profile) and `ProfileID` (the process)) and validators treat those as the contract for which rules apply.

What must the invoice contain?

EN 16931 defines the semantic core: seller and buyer identification, invoice number and issue date, currency, line items with quantities and net amounts, a VAT breakdown by rate category, and document totals. Two properties cause most real-world failures. The totals must agree arithmetically – line extensions, allowances, VAT category sums and the payable amount are cross-checked by rules, so rounding differences between your database and the XML fail validation. And identifiers are scheme-qualified: a seller’s registration or the buyer’s electronic address carries an ISO 6523 scheme (an Estonian registry code, for instance, under scheme 0191).

How is it validated?

In two layers, and the split matters when you debug. XSD validation checks structure – elements, order, data types; a failure here means malformed XML. Schematron validation checks business rules – the EN 16931 rules (codes starting `BR-`) and Peppol’s additional rules (codes starting `PEPPOL-`); a failure here means legal-content problems in well-formed XML. Good Access Point APIs run both synchronously before accepting the document, which turns a compliance failure into an ordinary API error your test suite catches. We unpack the error classes in Peppol validation errors explained.

Build the XML yourself or let an API generate it?

Both are legitimate; the trade-off is control versus maintenance. Building UBL directly (there are mature libraries in most ecosystems) gives you full control and offline generation, but you own rule-list updates – the Schematron rules evolve on the network’s release cycle. Sending structured JSON to an Access Point API that generates and validates the UBL removes that maintenance and typically comes with a sandbox, at the cost of a runtime dependency. A reasonable default: if e-invoicing is your product’s core, own the XML; if it is a feature, let the API do it and spend the saved weeks elsewhere.

What is the difference between UBL, EN 16931 and Peppol BIS 3.0?

UBL 2.1 is the XML syntax, EN 16931 the semantic content standard, and BIS Billing 3.0 a conformant EN 16931 profile in UBL plus Peppol network rules, declared via CustomizationID/ProfileID.

Why does my UBL invoice fail validation even though the XML is well-formed?

Well-formed XML passes XSD but can still break Schematron business rules — BR-* (EN 16931) or PEPPOL-* codes — typically arithmetic disagreements in totals or missing scheme-qualified identifiers.

Can I send JSON instead of UBL XML?

Some Access Point APIs accept structured JSON and generate the UBL for you; support varies by provider. On the network itself the document travels as UBL XML.

Should I build UBL generation myself?

If e-invoicing is your core product, owning the XML and rule updates makes sense. If it is one feature, an Access Point API that generates and validates UBL removes the maintenance burden.