Validate e-invoices properly
An XRechnung file lands in your inbox, your customer's system spits it back out, and the rejection never mentions BR-DE-15 or whichever numbered rule it actually broke. Those rules are public and they are free. Below is how I run them, which formats are genuinely covered, and the places where I would rather tell you the coverage is thin than let you discover it on a real invoice.
The questionHow do I check whether an e-invoice actually passes XRechnung, Peppol or EN 16931 validation?
How the working version is put together
Read what the file is, not what it is called
The root element and its namespace decide the format, so a file named invoice.xml gets treated as whatever it actually contains. A PDF is opened and the invoice XML pulled out of its attachment, which is how a hybrid file works: the readable PDF carries the machine-readable CII inside it. File names lie constantly and I would rather not build on one.
Run the rules the document says it follows
UBL declares its profile in CustomizationID and CII in the guideline parameter, and the value is a long URN naming XRechnung 3.0 or Peppol BIS Billing 3.0 or NLCIUS or plain EN 16931. By default a German invoice gets both the European core rules and the German ones on top, because that is what a German validator would do to it. You can override the whole thing and force any list of profiles when you want to know how a file would fare somewhere else.
Use the published artefacts and nothing home-made
EN 16931 comes from the Commission's own repository, XRechnung from KoSIT, Peppol from OpenPEPPOL, NLCIUS from the Dutch Peppol authority. Each one is downloaded at its tagged version, compiled ahead of time, then run through SaxonJS to produce SVRL like any other conformant validator. No rule is reimplemented and no rule is approximated. The version and download URL of every artefact is recorded inside the Actor so you can check what actually ran.
Hand back the rule id, never the word invalid
A failure arrives as BR-02 or BR-DE-15 or PEPPOL-EN16931-R008, with the severity the rule itself carries, the message in the language its authors wrote it in, and an XPath pointing at the element at fault. That is the difference between a developer fixing something this afternoon and a developer opening a ticket asking what the validator meant.
Name the rule sets that did not run
Every row lists the profiles that were checked and the profiles that were skipped, because a rule set with no official artefact for that syntax has to be visible. Silence must never read as a pass. A clean row that quietly checked nothing is worse than a failure, and it is the failure mode I trust least in every validator I have used.
What is actually covered
The EN 16931 core rules run over both UBL and CII. XRechnung 3.0 runs over both syntaxes against KoSIT's own Schematron, checked with their published test suite. Peppol BIS Billing 3.0 runs over UBL. NLCIUS and SI-UBL 2.0 run over the Dutch authority's artefacts. A Factur-X or ZUGFeRD PDF is handled by pulling the embedded CII out of the attachment and validating that.
Three more formats are checked against their official XSD schemas, which for those three is the rule set: Spain's Facturae, Italy's FatturaPA and Poland's KSeF FA(3). Everything above was verified against each body's own test files rather than against invoices I wrote myself, which is the only way to know a validator is reading the rules the same way its authors do.
Where the coverage is thin, said out loud
The Factur-X and ZUGFeRD profile rules are published inside a specification package rather than at a free stable URL, so a hybrid PDF is checked against the EN 16931 CII rules and not against the profile's own extra rules. Romania's RO_CIUS has no freely downloadable Schematron at all, so e-Factura is not covered.
For Facturae, FatturaPA and KSeF I can prove the schemas reject a malformed document, because I broke files deliberately and watched them fail. I cannot prove a clean pass on a real one, because no freely available valid sample exists for any of the three. So treat those as a shape check that catches broken files rather than as a guarantee.
The Peppol rules here are 3.0.21, the release that became mandatory on 17 August 2026, and the Dutch SI-UBL artefacts are the set that took effect the same day. Every artefact is pinned to an exact version, which makes a run reproducible and also means it goes stale if nobody looks. OpenPEPPOL never tagged 3.0.21 on GitHub, so I pinned the commit carrying the file they actually serve to implementers, after checking it matched byte for byte.
Why the deadlines are doing the work
Germany has required every business to be able to receive an e-invoice since 1 January 2025. Issuing them becomes mandatory on 1 January 2027 for businesses turning over more than 800,000 euro and on 1 January 2028 for everyone else. France moved on 1 September 2026: from that date every company has to be able to receive, and large and intermediate companies have to issue, with smaller firms following on 1 September 2027.
That is what turns a formatting question into a cash flow question. An invoice your customer's system refuses is an invoice nobody is paying yet, and the reason it was refused is a numbered rule sitting in a file somebody has to open.
What it costs to run
The hosted version on Apify charges one event per invoice it actually reads and validates, and the price is per invoice however many rule sets run over it. Checking a German invoice against the European rules and the German ones is one charge, not two. A URL that will not fetch costs nothing, a file that is neither XML nor PDF costs nothing, and running it empty gives you four bundled sample invoices for free so you can see the output before spending anything.
The cost that is not on the invoice is the same as everywhere else. Somebody has to decide what happens when a supplier's file fails: hold it, fix it, or send it back with the rule id attached. That decision is the actual work and no validator makes it for you.
When I would tell you not to bother
If you send twenty invoices a month to one customer whose system already accepts them, you have no problem here. This earns its keep when files are moving in volume between systems nobody controls end to end, or when a mandate has just landed and nothing has been tested.
If what you need is clearance from a tax authority, this is the wrong tool and I would rather say so. It checks the standard's rules and the national extensions on top. A tax office also checks registration and VAT numbers against its own register, along with timing and duplicates, and it can reject a file that passes every rule here. A green row means the format and the arithmetic are right, which is where most rejections come from, and it is not permission.
What lands on your desk
- One row per invoice, readable without opening the file
- Every failure with its real rule id, severity, message and XPath location
- The rule sets that ran and the rule sets that were skipped, always both
- A hosted Actor you point at files, with no key and no account anywhere
- If you want this wired into your intake so bad files never reach the ledger, that is the work I do
Open the proof
Published case studies of systems that are running. Each links to the thing itself.
The hosted Actor on Apify ↗The EN 16931 rules, from the European Commission ↗The XRechnung Schematron, from KoSIT ↗Peppol BIS Billing 3.0, the specification itself ↗The French mandate, on impots.gouv.fr ↗My n8n creator profile ↗
Questions this page answers
- Which e-invoice formats can you validate?
- EN 16931 core rules over UBL and CII, XRechnung 3.0 over both syntaxes, Peppol BIS Billing 3.0 over UBL, NLCIUS and SI-UBL 2.0, and Factur-X or ZUGFeRD PDFs by pulling out the embedded CII. Spain's Facturae, Italy's FatturaPA and Poland's KSeF FA(3) are checked against their official XSD schemas.
- Are these the real rules or an approximation of them?
- They're the published artefacts, downloaded at a tagged version from the Commission, KoSIT, OpenPEPPOL and the Dutch Peppol authority, then compiled and run to produce SVRL. Nothing is reimplemented, and the version and download URL of every artefact is recorded inside the Actor.
- What do I get back when an invoice fails?
- The rule id itself, so BR-DE-15 rather than the word invalid, along with the severity the rule carries, the message in the language its authors wrote it in, and an XPath to the element at fault.
- What isn't covered?
- I don't cover Romania's RO_CIUS at all, because no free Schematron exists for it. Factur-X and ZUGFeRD hybrid PDFs I check against the EN 16931 CII rules only, since the profile's own rules aren't published at a free stable URL.
- Does a clean result mean the tax authority will accept my invoice?
- No, and I'd rather be blunt about it. This checks the standard's rules and the national extensions. A tax office also checks registration, VAT numbers, timing and duplicates, and it can reject a file that passes every rule here.
Want this built and handed over working?
One line is enough to start. You get an honest answer on fit, and a number rather than a discovery call.
Start a brief