EN 16931 rules explained

An e-invoice is validated in layers: the XML schema of its syntax (UBL 2.1 or CII D16B), the business rules of the European norm EN 16931 (published by CEN as schematron, release 1.3.16 today), then the rules of the specification it claims (XRechnung for Germany, Peppol BIS Billing 3.0 on the Peppol network). Every rule has an id that says which layer and which family it belongs to: read the prefix and you know where to look. The ten failures below are the ones the engine’s tests and the evidence run produce most often.

The layers above the norm

A CIUS (core invoice usage specification) narrows EN 16931 for one community. XRechnung adds BR-DE-* rules (buyer reference, seller contact, payment instructions) and carries a few Peppol rules (PEPPOL-EN16931-R010 and R020: both electronic addresses). Peppol BIS Billing 3.0 adds PEPPOL-EN16931-R* (one note at most, a buyer or order reference, no empty elements), PEPPOL-EN16931-CL* code lists, PEPPOL-COMMON-* identifier checks (R043: the Belgian enterprise number) and national rule sets (DE-R, NL-R, NO-R, SE-R …).

A ZUGFeRD / Factur-X EN 16931 file is held to EN 16931 alone: no BR-DE rule applies unless the file claims XRechnung.

Severities, and who may change them

Each rule carries a flag: fatal rejects the document, warning does not. A validator configuration may change the level of a rule for its community: the KoSIT XRechnung configuration lowers BR-CL-23 (unit code) and BR-CL-21 (item scheme) to warnings and raises UBL-CR-646 and some CII-SR rules to errors. The same file can therefore pass as an XRechnung and fail as a Peppol document. The Veriport validator applies the KoSIT levels to XRechnung documents, and the evidence shows it reaches the same verdict as KoSIT on every sample.

The ten failures seen most, and the fix

RuleWhat it saysFix
BR-CO-10The sum of line net amounts (BT-106) is not the sum of the linesCompute BT-106 from the rounded line nets, not from unrounded quantities × prices.
BR-CO-13Total without VAT (BT-109) ≠ lines − allowances + chargesWrite BT-107 / BT-108 when there are document-level allowances or charges, and subtract or add them.
BR-CO-14Total VAT (BT-110) ≠ the sum of the breakdown tax amountsSum the VAT of the breakdown groups, not the VAT of each line.
BR-CO-15 / BR-CO-16Total with VAT or amount due does not add upBT-112 = BT-109 + BT-110; BT-115 = BT-112 − paid + rounding.
BR-S-08A breakdown taxable amount is not the lines of that rate minus allowances plus chargesOne breakdown per category and rate, allowances and charges of the same rate included.
BR-CO-17Breakdown VAT is not taxable × rate, roundedRound the VAT per breakdown group, once, to two decimals.
BR-DE-15XRechnung without buyer reference (BT-10)Give the buyer reference: the Leitweg-ID for a German public body, else the order number or cost centre.
PEPPOL-EN16931-R010No buyer electronic address (BT-49)Give the buyer’s address: e-mail under EM for XRechnung, a Peppol identifier (0208, 9944 …) on Peppol.
BR-33 / BR-38A document-level allowance or charge without reason or reason codeGive a reason text, a reason code (UNCL5189 / UNCL7161), or both.
BR-CL-23Unit code outside UN/ECE Recommendation 20/21Use C62 (piece), HUR, DAY, MON, KGM, LTR, LS…; XRechnung reports it as a warning, Peppol as an error.

Reading a validation report

POST https://veriport.io/api/v1/einvoice/validate answers with valid, the detected profile and two lists. Each finding has the rule (as published, or XSD for a schema error), the severity, the path (an XPath to the element, or the line of a schema error), the published message (CEN and Peppol in English, the BR-DE rules in German) and the source (schema, cen-ubl, xrechnung-cii, peppol-ubl …). Findings with source: "veriport" are Veriport’s own checks of national practice (a German VAT number check digit, a Belgian structured communication): never published rules, always warnings.

curl — validate a file (no key: 4 checks a day per address)
curl -X POST "https://veriport.io/api/v1/einvoice/validate" \
  -H "Content-Type: application/xml" \
  --data-binary @invoice.xml

Preventing the arithmetic failures

Most rejected invoices fail BR-CO-* because totals were computed from unrounded values. The rules expect line nets rounded to cents first, then sums of those, VAT computed once per category and rate. POST https://veriport.io/api/v1/einvoice/create does not take totals from the caller: it computes them from the lines, allowances and charges, so these rules hold by construction, and it refuses a caller’s totals field rather than ignoring it.

Questions

Where are the rules published?
CEN TC 434 publishes the EN 16931 validation artefacts (schematron for UBL and CII) with the European Commission; KoSIT publishes the XRechnung rules; OpenPeppol publishes the Peppol BIS rules. The sources below link each release.
Why does the same rule id appear twice in a report?
A rule fires once per element it applies to: two lines with a wrong unit code give two findings with the same id and two paths.
Can I check a file without an account?
Yes, 4 checks a day per address on the XRechnung, Factur-X and Peppol tool pages.

5 calls a check, the published rule ids, no document stored.

Validate a file by API

Sources