One POST. No account, no key, no signup. Send an invoice, get back every rule it breaks with the reason and the fix.
curl -X POST --data-binary @invoice.xml \ -H 'Content-Type: application/xml' \ https://invoicevalidator.eu/v1/validate?profile=peppol
Or as a file upload — this is also how you send a Factur-X / ZUGFeRD PDF:
curl -F file=@invoice.pdf https://invoicevalidator.eu/v1/validate
Body: the invoice, either as a raw XML/PDF body or as multipart with a file
part. Maximum 5 MB.
| profile | Which rule set to check against.
en16931 = EN 16931 (core). peppol = Peppol BIS Billing 3.0 (+ national rules). xrechnung = XRechnung 3.0.2 (Germany). Defaults to en16931.The Peppol profile also carries the national rule sets for Germany, Denmark, Greece, Iceland, Italy, the Netherlands, Norway and Sweden. They switch on by themselves from the seller's country — a Norwegian seller is checked against NO-R-* as well, with no extra
parameter. |
| syntax | ubl or cii. Auto-detected from the
root namespace if omitted; you should not normally need it. |
{
"syntax": "ubl",
"profile": "peppol",
"source": null, // PDF attachment the XML came from, if any
"valid": false, // true when there are no fatal findings
"counts": { "fatal": 2, "warning": 0 },
"findings": [
{
"rule": "BR-CO-17",
"severity": "fatal",
"message": "VAT category tax amount (BT-117) = ...",
"cause": "In a VAT breakdown group the VAT category tax amount ...",
"fix": "Set BT-117 = round(BT-116 x BT-119 / 100, 2) per breakdown group ...",
"confidence": "curated", // curated | template | none
"line": 25,
"excerpt": [ { "line": 24, "text": "..." } ],
"location": "/Invoice/TaxTotal/TaxSubtotal",
"business_terms": ["BT-116", "BT-117", "BT-119"]
}
]
}
confidence tells you where the wording came from: curated is written by
hand, template is generated from the rule's own shape, none means only the
official rule text is available. It is exposed so you never have to guess.
A ZIP of invoices in, one result per file out — the shape of the job if you build accounting software and want to know which of your generated invoices are wrong.
curl -F file=@invoices.zip https://invoicevalidator.eu/v1/validate/batch?profile=peppol
Limits: 20 MB archive, 200 files, 60 MB uncompressed, 5 MB per invoice.
A file that cannot be read comes back with an error instead of findings, so one bad
document never fails the batch.
The whole catalogue. Filter with ?syntax=ubl, ?category=model,
?severity=fatal.
One rule with its cause, fix and the XPath actually evaluated, per syntax. Case-insensitive:
https://invoicevalidator.eu/v1/rules/br-co-17.
| 429 | Rate limit — 20 validations and 240 reads per minute per IP. |
| 422 | A PDF with no embedded invoice XML. A printed PDF is not a Factur-X invoice; the message says so. |
| 400 | Empty body, or XML that cannot be parsed. |
| 413 | Larger than 5 MB. |
Machine-readable schema: /openapi.json · interactive: /docs.
Invoices are validated in memory and never written to disk or logged. There is no account, so there is nothing to delete. The only thing kept is an anonymous daily count of how many validations ran and how many pages were served — no IP addresses, no user agents, no document content.