Originally published at https://arling.sk/notes/peppol-invoice-validator-what-it-checks/
Peppol Invoice Validator: What It Checks and What It Misses
A Peppol invoice validator should run three layers: the UBL 2.1 XML Schema, the EN 16931 rules and the Peppol BIS Billing 3.0 rules. An invoice is compliant when no fatal error comes back, and warnings alone do not change that. Before you trust a clean result, check which profile the validator detected and which release of the rules it runs. We broke one sample invoice eleven ways: our own browser check flagged eight, one of them only with a warning where Peppol has a fatal error, and it missed a swapped element order, an extra ProfileExecutionID and a shortened CustomizationID.
This matters to anyone who sends invoices over Peppol, and in Slovakia it becomes routine: e-invoices between domestic VAT payers are mandatory from 1 January 2027 and travel over the Peppol network through certified providers. Slovakia uses Peppol BIS Billing 3.0 directly, with no CIUS of its own. Below you will find what each layer checks, how to read fatal and warning, every result of our test with the free ARLing Peppol validator, and which free validators to use, including where ours falls short.
Three layers, three different questions
The first layer is the UBL 2.1 XML Schema (XSD), and it checks structure only: which elements occur where, how often and in which order. The free validator from ecosio lists it as the second of its three stages: well-formed XML, the XML Schema, then the Schematron rules. Our browser check skips this layer, which is why a swapped pair of dates went through it unnoticed in the test below.
The second layer is EN 16931, the European core invoice model, with its BR rules and the BR-CO rules for totals and consistency. The third is Peppol BIS Billing 3.0, which sits on top of EN 16931 in the UBL 2.1 syntax and adds its own PEPPOL-EN16931-R and PEPPOL-COMMON-R rules. Both rule sets are published as Schematron files on the Peppol BIS Billing 3.0 page.
Some countries keep their rules inside the Peppol file itself: of the 166 checks in release 3.0.21, 102 are national rules for Germany, Denmark, Greece, Iceland, Italy, the Netherlands, Norway and Sweden. Germany also has XRechnung, its national CIUS with its own BR-DE rules, for example BR-DE-15 for the buyer reference. There is no Slovak rule in the file. The Slovak national requirements (PASR) mainly set the network identifier, schemeID 0245 followed by the ten digit tax number DIČ, and nothing in the official files checks that the DIČ is really there.
Fatal or warning: which findings stop an invoice
A sender shall not send a message that is not compliant, a receiver may reject one, and a compliant message shall not be rejected.
In the current EN 16931 Schematron for UBL, version 1.3.16, we counted 979 checks: 281 fatal and 698 warning. Of those warnings, 676 are UBL-CR rules, 21 are UBL-DT rules and only one is a BR rule, BR-51. The Peppol file of release 3.0.21 is the other way round: 166 checks, 139 fatal and 27 warning.
A UBL-CR warning usually means the file carries an element the core invoice does not use, for example "[UBL-CR-003]-A UBL invoice should not include the ProfileExecutionID".
We broke one sample invoice eleven ways
The test file was the made-up English sample from our e-invoice check: invoice 2026-0142, Peppol BIS Billing 3.0, reverse charge, 1500.00 without VAT. Unchanged, it passes with no errors and no warnings. On 25 September 2026 we changed one thing at a time and ran our check in Node over every variant.
- Only the total with VAT raised by one cent, to 1500.01: BR-CO-15 for the total itself and BR-CO-16, because the amount due no longer equals the new total.
- Currency code EURO instead of EUR: 13 errors, BR-CL-04, BR-CO-15 and eleven times PEPPOL-EN16931-R051, one for every amount that still says EUR.
- Empty invoice number: BR-02 and PEPPOL-EN16931-R008, "Document MUST not contain empty elements."
- A typo in the IBAN: ARL-IBAN, our own mod 97 check. The official Peppol rules check the IBAN only when supplier and customer are both in Germany, and then only as a warning, so a validator with those rules lets this through.
- Issue date written as 11.09.2026: ARL-DATUM and PEPPOL-EN16931-F001, "A date MUST be formatted YYYY-MM-DD."
- An element left unclosed: XML-01 and nothing else, because no rule can run on broken XML.
- A Slovak endpoint with schemeID 0245 holding SK2020000000, a VAT number instead of the DIČ: ARL-SK-DIC-TVAR, again our own check. No official rule checks that a ten digit DIČ follows 0245, so a validator with the official rules lets this through.
- An unknown CustomizationID: only one warning in our check, ARL-PROFIL, and only the EN 16931 core rules ran. A validator that runs the Peppol rules stops this file with the fatal rule PEPPOL-EN16931-R004.
Two things to take from this. A single mistake can fill a report: the EURO file produced 13 lines from one wrong code, so fix the first error of each kind and run the check again. And one cent is enough, because BR-CO-15 compares the totals with no tolerance, and that test is the same in version 1.3.16.
Three mistakes that passed without a single finding
Swapping the order of cbc:IssueDate and cbc:DueDate gave zero findings in our check. Element order is the job of the XML Schema, and our browser check does not run it.
Adding a cbc:ProfileExecutionID element also passed with zero findings, because we do not run the UBL-CR group. A validator with the official EN 16931 files would list it as the warning UBL-CR-003.
The third one is the dangerous kind. We shortened CustomizationID to urn:cen.eu:en16931:2017, and our check did exactly what it is built to do: it read the field, detected plain EN 16931 and evaluated 230 rules instead of 289. There was no error because the Peppol rules never ran, while the official fatal rule PEPPOL-EN16931-R004 requires the Peppol value in that field. So read the profile line and the rule count before you believe a report with zero errors.
Which free validator to use, and which release it runs
Free validators you can use today, each with a different scope:
- The ecosio validator checks well-formed XML, the XML Schema and the Schematron rules, lists Peppol BIS 3.0, UBL, CII and XRechnung among its formats, and says it deletes a file once the result is displayed. It uses the validation engine of Philip Helger, and the upload page of his Peppol Practical site now points there. We could not confirm which release of the rules its form offers, so look for 3.0.21 before you rely on the result.
- The eInvoice Validator of the European Commission checks EN 16931 in UBL and CII with release 1.3.16, but offered no Peppol BIS Billing 3.0 or XRechnung type when we looked, so it stops at the core rules.
- The KoSIT Validator, with the KoSIT configuration for XRechnung, is a program for Java 11 or later that you start from the command line; it runs the XML Schema and the Schematron rules and computes an acceptance status.
Whichever you pick, check the release. Peppol publishes its rules in numbered releases: release 3.0.21 came out on 20 May 2026 and has been mandatory since 17 August 2026, together with version 1.3.16 of the EN 16931 artefacts. Compliance is measured against the current artefacts, so a validator on an older release answers a slightly different question.
The changes look small but they bite: BR-CO-25 was removed, R007 now accepts only a list of approved business process identifiers that includes a new profile 02 and two French profiles, and PEPPOL-COMMON-R052 and R053 changed from warnings to errors. One trap caught us too: on 25 September 2026 the docs.peppol.eu files page served release 3.0.21, while the master branch of the GitHub repository still held 3.0.20.
Our own check was built from those GitHub files on 10 September 2026, so it runs release 3.0.20. In practice it still reports BR-CO-25 for an invoice with a positive amount due and neither a due date nor payment terms, and it reports R007 for the new profile 02 identifier and for a French profile, although release 3.0.21 allows them. It also lets urn:fdc:peppol.eu:2017:poacc:billing:02:1.0 through without a finding, a value release 3.0.21 does not approve.
FAQ
Is an EN 16931 validator enough for a Peppol invoice?
No. Peppol BIS Billing 3.0 adds its own PEPPOL-EN16931-R and PEPPOL-COMMON-R rules on top of EN 16931, and the European Commission validator we tried offered only EN 16931 types. Use a validator that also runs the Peppol Schematron.
Can I send an invoice that still shows warnings?
Yes, as long as none of the findings is fatal: a receiver shall not reject a compliant message. Most warnings in the EN 16931 file are UBL-CR rules about elements the core invoice does not use.
Why does my validator still report BR-CO-25?
Most likely because it runs rules older than release 3.0.21. The release notes of 3.0.21, mandatory since 17 August 2026, list BR-CO-25 as removed, and the rule is not in the current file. Our own check reports it for the same reason, as described above.
Which free Peppol validator also checks the XML Schema?
The ecosio validator describes a three stage check: well-formed XML, the XML Schema, then the Schematron rules. The KoSIT Validator runs the XML Schema too, but from the command line. Our browser check does not run it.
Does any official rule check the Slovak 0245 identifier?
Only that 0245 is an allowed scheme. In the Peppol file of release 3.0.21 the code appears only in the list of allowed electronic address schemes, rule PEPPOL-EN16931-CL008, and no check verifies that the ten digit DIČ follows it. Our check reports a VAT number in that place as ARL-SK-DIC-TVAR.
Does a clean result mean the buyer will accept my invoice?
Only for what was actually checked. A clean run with the current artefacts means the file is compliant with the BIS. A partial check like ours, which skips the XML Schema and the UBL-CR, UBL-SR and UBL-DT rules, does not guarantee acceptance by the buyer or the network.
Check your own file
Load your XML into the free ARLing Peppol validator: it reads the file in your browser, shows the detected profile and the number of rules it evaluated, and lists every finding with the rule code, the value from the file and the original wording of the rule. It still runs release 3.0.20, so if it reports BR-CO-25, or R007 for profile 02 or a French profile, the mistake is in our rules, not in your file. It also runs two checks the official files do not make on a Slovak invoice, the IBAN checksum and the DIČ after 0245. Before a large batch goes out, also run the file through a full validator such as the free one from ecosio, which checks the XML Schema and the Schematron rules. The same e-invoice tools also draw the XML as a readable document, so you see the invoice the way a person reads it.
ARLing also has a free e-invoicing tool.
Top comments (0)