The guideChapter 04
The invoice itself
Business terms, the totals ladder that has to reconcile exactly, and the VAT breakdown that is not one number.
By now you have a network that can carry a document and an identifier that says where it goes. This chapter is about the document.
Three names get used loosely and it is worth pinning them down, because they are three different things.
EN 16931 is the European standard. It is a semantic model: it says
what an invoice means, not what it looks like. Every piece of an invoice
gets a code, BT-1 for the invoice number, BT-5 for the currency,
BG-25 for the group that is an invoice line. Nothing in it is XML.
Peppol BIS Billing 3.0 is a profile of that standard, narrowed. Where EN 16931 permits a choice, the profile often makes it for you, and it adds rules of its own. The current release is 3.0.21.
UBL 2.1 is the syntax: the XML that carries the model.
So the document you have to produce is UBL 2.1, shaped by EN 16931, and constrained further by Peppol. When a validator tells you something is wrong it will name the rule, and the rule tells you which of those three is unhappy.
Business terms are the vocabulary
Once you know the codes, the rules become readable. BR-02 says “An
Invoice shall have an Invoice number (BT-1).” It is not asking for a field
called number; it is asking for the thing that means “the invoice’s
number”, which in UBL happens to be cbc:ID.
That indirection is the point. The same semantic model can be expressed in UBL or in CII, and a rule written against business terms holds for both. It also means an error message that only quotes XPath is doing half a job: you want the business term, because that is what maps back to your own data model.
A handful you will meet immediately:
BT-1invoice number,BT-2issue date,BT-5currencyBT-27seller name,BT-44buyer nameBT-10buyer reference,BT-13purchase order referenceBG-25invoice line,BT-131line net amountBT-109total without VAT,BT-110total VAT,BT-112total with VAT
The minimum
Strip away everything optional and a valid invoice still needs an invoice
number, an issue date, a currency, both party names, and at least one
line. Those are BR-02, BR-03, BR-05, BR-06, BR-07 and BR-16,
and they are the five-second sanity check on any document your code
produces.
Peppol adds one that catches people out, because no other system has ever
asked for it: a buyer reference or a purchase order reference, on every
invoice. That is
PEPPOL-EN16931-R003, and if your
application has no field for either, it is the first thing to add.
The totals have to reconcile
This is where most rejections come from, and it is arithmetic rather than structure.
The totals form a ladder. Each line has a net amount, BT-131. Those sum
to BT-106, the sum of line net amounts, which is BR-CO-10. Take off
document-level allowances and add document-level charges and you get
BT-109, the total without VAT, which is BR-CO-13. Add the total VAT,
BT-110, and you get BT-112, the total with VAT, which is BR-CO-15.
Then subtract anything already paid and you get the amount payable.
Every one of those is an equality that has to hold exactly, which is why chapter 1 insisted on decimals rather than floats. Two invoices out of a thousand failing on a rounding difference of a penny is not an edge case, it is a Tuesday.
The safest approach is to stop storing totals as decisions and start
computing them from the lines at the moment you build the document. If
your system holds a total that somebody once typed, and the lines say
otherwise, the document will say so too. POST /v1/conversions takes
lines and computes the ladder for you, precisely so this class of failure
cannot happen.
VAT is a breakdown, not a number
In your database VAT is probably one column. In the document it is a group,
BG-23, repeated once per combination of category and rate, each carrying
the taxable amount and the tax amount for that combination.
The category codes are the part worth learning:
Sstandard rateZzero ratedEexemptAEreverse chargeKintra-community supplyGexport outside the EUOoutside the scope of VAT
They are not interchangeable labels for “no VAT”. Each carries its own
rules. BR-E-10 requires an exemption reason on an exempt breakdown.
BR-AE-10 requires one on reverse charge. BR-Z-10 says a zero-rated
breakdown must not have one. Getting the category right and the reason
wrong is a rejection; so is the reverse.
If your invoicing code has a boolean for “VAT applies”, this is the section that will cost you the most, and it is worth finding out now rather than in the quarter you have to ship.
Parties, and what they need
A party is more than a name. Each side needs a name, a postal address with a country code, and for the seller a VAT identifier where one applies. The electronic address is the Peppol identifier from chapter 3, and it is a different thing from the postal address and from the VAT number, even when it contains the VAT number.
A registration name and a company number can both appear, and this is where the UK shape gets slightly awkward: the company number has a home in the document, and no home on the network.
Lines
A line needs an identifier, a name, a quantity with a unit of measure, a
net price, and a VAT category. The unit code comes from a published list
rather than free text, so “each” is C62, and a line that says hours
will be rejected where one that says HUR is not.
Line-level detail is another place where invoicing software has usually taken a shortcut. A single line that says “Consulting, £1,000” is a valid invoice. It is also the point at which a buyer’s system cannot match your invoice to their purchase order, which is the entire reason they wanted an e-invoice.
Credit notes
A credit note is the same document with BT-3 set to 381 instead of
380, and a reference to the invoice it corrects, BG-3. Everything
above still applies: the totals ladder, the VAT breakdown, the parties.
There is no separate schema to learn, which is a relief, and no separate
code path worth writing.
What this means for your model
Reading the standard, the mapping tends to come out like this:
- You have a number, a date, a currency and two parties, and they map cleanly.
- You have totals, and they should be computed rather than mapped.
- You have a VAT figure, and it needs to become a breakdown.
- You have lines, and they need a unit code and a category per line.
- You have no buyer reference, and you need one.
Which is a morning’s schema work and a week of thinking about tax categories. Once the document exists, the next question is whether it passes, and that is chapter 5.
Checked against its sources on 18 September 2026
One email when the guide is finished, and an explainer on Budget day.
Getting a key, validating a document, and the API reference.