InvoiceKit

Validate an EN 16931 e-invoice without handing it to anyone

Paste or drop a Factur-X, ZUGFeRD, XRechnung or Peppol invoice XML and get the official European Commission business rule report back. The checker runs in this page, on your machine — your invoice is never uploaded.

Why it exists. Structured e-invoicing has stopped being optional: every business in Germany must be able to receive one since January 2025, with sending phased in during 2027–28, and France follows in 2026–27. So millions of invoices now have to satisfy a rulebook nobody reads, and the validators that do exist mostly want the file uploaded to someone’s server, or want a subscription. This is that rulebook as a static page — the same engine that runs the command-line tool and the Go library, with no account and no upload.

UN/CEFACT CII and OASIS UBL 2.1 · rule sets v1.3.17 · free, no account, no email

Got a Factur-X or ZUGFeRD PDF instead of the XML? Audit the PDF itself — PDF/A-3, the attachment, and the XML inside it, also without uploading. Starting from a plain PDF instead? Add the Factur-X part to it. No invoice yet? Write one from a form.

Invoice XML

or drag a file onto the box, or paste below.

the engine starts on your first check

Report

Nothing to report yet. The engine loads once, then every check is local.

What the invoice says

The same bytes read back as an invoice instead of as a rule report: the number, the parties, the amounts and the lines exactly as the document states them. Nothing is recomputed here, so a total that disagrees with its lines stays on the page next to the rule that says so.

The same document read back as an invoice: number, parties, amounts and lines exactly as written.

Converted document

Nothing converted yet. Conversion runs here, in this tab, on the bytes you pasted — nothing is uploaded and nothing is stored.

What is checked

The page runs the same engine as the InvoiceKit Go library and CLI: an XPath 2.0 evaluator and Schematron runner written from scratch, with the official CEF validation artefacts built in. No Java, no XSLT, no server call.

Rule phases applied by default
SyntaxPhasesExamples
CII — Factur-X, ZUGFeRD, XRechnung EN16931-model-phase, codelist_phase, syntax_phase BR-21 invoice number, BR-CO-10 line total vs document total, BR-DEC-04 VAT category totals
UBL — Peppol BIS, OpenPeppol EN16931model_phase, codelist_phase BR-32 payable amount, BR-54 buyer country code, BR-ABC-04 allowance arithmetic
Optional rule sets — choose one beside the Validate button
Rule setHow it appliesExamples
XRechnung CIUS 2.6.0 (XRechnung 3.0.2), Germany Adds national rules on top of EN 16931 BR-DE-15 buyer reference, BR-DE-21 XRechnung specification identifier, BR-DE-28 tax number format
Peppol BIS Billing 3.0, release 3.0.21 Runs the network's own copy of EN 16931 in place of ours, so the report matches what an access point says PEPPOL-EN16931-P0100 invoice type code, PEPPOL-EN16931-CL001 media type, PEPPOL-COMMON-R040 GLN check digit

Accuracy is measured, not claimed. The engine reports zero findings on all 44 documents in the CEF reference sets (29 UBL, 15 CII), and passes 2,165 third-party conformance documents — 1,140 for EN 16931, 494 Peppol, 531 national — in which 953 named rules must fire and 1,064 must not. Mutations tell the other half of the story: on 148 doctored invoices, every expected finding appeared.

Rule coverage is the honest part. Every assert in the rule sets we ship has an ID, and the same tooling counts how many have actually been seen firing. The model-phase rules people care about — the BR-* families — are proven on 184 of 201 UBL and 105 of 200 CII asserts; codelist rules are complete (22 of 22, and 22 of 23). The rest are syntax and datatype asserts (UBL-CR-*, UBL-DT-*), proven on 65 of 759 and 44 of 587, where the schema check usually reports the same problem first. Every unproven ID is listed by name in the repository, and the list shrinks with each mutation run.

Structural validity against the syntax’s XML schema is reported separately from the business rules, in the schema section of the report. Factur-X and ZUGFeRD PDF envelopes are audited on their own page, the Factur-X checker. What is not checked here is delivery — an access point's transport rules — and further national schemes are added one at a time. Conformance checking is not legal or tax advice.

Run it in your pipeline instead

Browsers are for a quick look. For invoices you generate every day, put the checker where the invoices are made.

Command line

einv validate invoice.xml
einv check dist/invoices/*.pdf

Exit 0 clean, 1 findings that get a document rejected, 2 unreadable — so it fails a build rather than a customer. -json for machine output.

Go

go get github.com/dcnws/einvoice

One import, no CGO, no external processes. einvoice.Validate(data, einvoice.Options{}).

TypeScript

npm install @invoicekit/einvoice

The same WebAssembly module, packaged with types, for Node and the browser.

Status: the CLI, Go module and npm package are built from the engine running on this page but are not published yet — github.com/dcnws/einvoice goes public with the hosted API. The page itself is free to use either way.

Frequently asked

What is EN 16931?

The European norm defining the core semantic elements of an electronic invoice — what a seller, a VAT breakdown, a due date or a line allowance have to mean. National and private schemes (Factur-X, ZUGFeRD, XRechnung, Peppol BIS, Norway’s EHF, and others) are constrained subsets of the same model, which is why a single validator can serve all of them.

Is my invoice uploaded, stored or logged?

No. The validator is a WebAssembly binary that runs in this tab. Input never leaves your machine; there is no backend for it to travel to. The page works with the network unplugged after it has loaded.

My document is rejected as “not an EN 16931 invoice”. Why?

The root element must be a CII rsm:CrossIndustryInvoice, an OASIS UBL Invoice or CreditNote. A Factur-X PDF is not XML — the Factur-X checker reads the factur-x.xml attachment out of the PDF for you. Orders, quotations and credit memos in other formats are not invoices.

Why does it pass here but fail at my access point?

Access points validate XML schema validity first, then EN 16931, then a national or profile layer. Pick the matching layer in the Rule set dropdown: Peppol BIS Billing 3.0 runs the artefacts OpenPEPPOL publishes, XRechnung runs the German CIUS on top of the norm, and both check the XML schema first. Other national layers (EHF, the Nordic profiles, France’s) are not in this build. Compare the failing rule IDs — an id that appears nowhere in the report comes from a layer this build does not carry. If the document is a PDF, the Factur-X checker covers the envelope checks access points run before any of that.

Can you convert my invoice between CII and UBL?

Yes. Convert to the other syntax rewrites a UN/CEFACT CII document as OASIS UBL, or a UBL document as CII, in this tab, and then validates the document it wrote against the rule set in the dropdown — so a German XRechnung turned into UBL for a Peppol supplier is judged by the artefacts that supplier’s access point will run. Both syntaxes are encodings of the same EN 16931 model, so conversion is normally lossless. When the source carries something the model has no term for, the page lists what did not survive instead of handing back a document that quietly dropped it.

Why show the invoice as well as the rules?

Because the expensive mistake is a document that is rejected for one total while it states another. The rule report answers “does this conform”; the table beside it answers “what does it say”, and reading XML to find out is how a mismatch survives all the way to a payment run. The figures shown are the document’s own — this page would rather show you a wrong total than silently fix it, because a corrected total is a new invoice and not your invoice.

Is the tool really free?

Yes, and it needs no account. The engine is open source (MIT, with the European Commission’s EUPL-1.2 rule artefacts embedded unmodified). Paid work is elsewhere: hosted pipelines, batch checking and generation. If that changes anything about this page, it will say so here.