E-invoicing Compliance¶
Check an invoice against a published e-invoicing ruleset, get the XML, or get a PDF with the XML inside it.
What this is. A growing number of jurisdictions require invoices to be machine-readable and to satisfy a published rule set — not a PDF that happens to contain the right words. This API builds that document and holds it to the actual rules, so you find out before you send rather than from a counterparty weeks later.
What this is not. We do not transmit. Getting a document onto the Peppol network is the Access Point role — membership, certificates, accreditation — and we are not one. We make the document correct; your access point, or your customer's, moves it. Factur-X needs no network at all: it is emailed like any other PDF.
Profiles¶
A profile is a ruleset a document is built and validated against. There is no default: a document valid under one can be rejected by another, so the choice is the question rather than something to guess at.
profile |
Syntax | Rules run | Where it is used |
|---|---|---|---|
factur_x_en16931 |
CII, inside a PDF/A-3 | EN 16931 1.3.16 | France and Germany, by agreement rather than mandate |
peppol_bis_billing_3 |
UBL | EN 16931 1.3.16 + Peppol BIS Billing 3.0.20 | The Peppol network — EU public sector, NHS England, and the UK from April 2029 |
xrechnung_ubl |
UBL | EN 16931 1.3.16 + XRechnung 3.0 | German public authorities |
xrechnung_cii |
CII | EN 16931 1.3.16 + XRechnung 3.0 | German public authorities |
XRechnung appears twice because it is defined in both syntaxes, and they are not the same document. Ask the receiver which one they take.
GET /api/v1/reference/tax-categories, /tax-schemes and /unit-codes return
the coded lists these rules require. See Reference Data.
Peppol is not the EU
Italy clears through SdI, France through its PDP model, Poland through KSeF.
These are national platforms, not Peppol, and each is a separate
implementation rather than a profile. peppol_bis_billing_3 covers an
Italian invoice sent over Peppol, which is not the same thing as
FatturaPA's domestic mandate.
US invoices
EN 16931 is a European VAT standard. Its rules test the tax scheme against
the literal string VAT (BR-47, BR-48, BR-CO-17), and the US has no VAT —
sales tax is state and local, with no invoice-format requirement attached.
There is nothing here for a US-only business to comply with, and the API
will say so rather than relabelling a sales tax. For that business the PDF
is the invoice.
Validate Compliance¶
Checks a document and returns everything both tiers had to say about it. Nothing is stored, no PDF is produced, and it does not count against your render quota — so you can check every invoice you are about to send.
A document that satisfies its profile:
{
"data": {
"profile": "factur_x_en16931",
"ruleset_version": "EN16931-CII 1.3.16",
"valid": true,
"in_scope": true,
"fully_checked": true,
"rulesets": [
{"id": "semantic", "label": "Mandatory fields", "version": "", "ran": true, "reason": null},
{"id": "en16931-cii", "label": "EN 16931 (CII)", "version": "1.3.16", "ran": true, "reason": null}
],
"violations": []
}
}
One that does not:
{
"data": {
"profile": "peppol_bis_billing_3",
"ruleset_version": "EN16931-UBL 1.3.16 + Peppol BIS Billing 3.0.20",
"valid": false,
"in_scope": true,
"fully_checked": true,
"violations": [
{
"rule": "BT-10",
"path": "buyer_reference",
"message": "Peppol BIS Billing 3.0 requires a buyer reference unless an order reference is present, and this document carries neither.",
"severity": "fatal",
"ruleset": "semantic"
}
]
}
}
Reading the answer¶
There are four fields that mean different things, and conflating them is the usual mistake.
valid — nothing found would get this document rejected. It is not "no
findings": both EN 16931 and Peppol grade a large share of their rules as
advisory, and a document reported invalid over a recommendation would be a
verdict nobody could use. Only severity: "fatal" counts.
fully_checked — every ruleset that applies actually ran. This is a
separate question from the verdict, and the one people miss. The
authoritative tier executes the published Schematron artefacts; if that
toolchain is unavailable, the document is still checked against the
mandatory-field rules and valid can come back true — but on a materially
weaker basis. A ruleset that could not run is never reported as a pass.
Check fully_checked before you treat valid: true as an answer, and see
rulesets[].ran and .reason for which one and why.
in_scope — whether these rules mean anything for this document at all.
false for an invoice with no party in a country that uses them: a verdict of
"an access point would reject this" names a rejection that cannot happen. It
never changes valid — it tells you whether the verdict is worth having.
ruleset_version — which artefact versions ran. These are published
documents that get revised, so "which rules did this pass?" is answerable only
with the version beside it.
Severity¶
severity |
Meaning |
|---|---|
fatal |
A receiver is entitled to reject the document. Sets valid: false. |
warning |
Advisory. Worth reading, not a rejection. |
rule is the identifier the standard uses — BT-10 from the mandatory-field
tier, PEPPOL-EN16931-R003 from Schematron — which is what a rejection notice
from an access point quotes back at you. path locates it: a field of your
request from the first tier, an XPath into the generated XML from the second.
Try it
Get the XML¶
The document as UBL or CII, in the syntax its profile is expressed in. Stateless — send the data, get the XML.
The same, for a document you have stored.
This is the file you hand to an access point. We do not send it for you.
Try it
Try it
Factur-X: the PDF with the XML inside¶
Pass format: "facturx_pdf" instead of "pdf" on any render call and you get a
PDF/A-3 carrying factur-x.xml — a human-readable invoice and a
machine-readable one, in a single file that needs no network and no counterparty
agreement. It is emailed like any other PDF.
This path fails closed. The document is checked before it is rendered, and
a fatal violation means no PDF is produced — you get 422 with
code: "compliance_failed" and every violation in details, not just the first.
A file that claims EN 16931 conformance and does not have it is worse than no
file, because the claim travels with it.
The embedded XML is the exact bytes that were validated, not a second serialization of the same document.
What the render records¶
A render made this way carries what it was held to:
{
"data": {
"id": "rnd_01ABC",
"format": "pdf",
"compliance": {
"profile": "factur_x_en16931",
"ruleset_version": "EN16931-CII 1.3.16",
"fully_checked": true,
"advisories": []
},
"download_url": "https://invoicepdfs.com/api/v1/renders/rnd_01ABC/download?token=..."
}
}
compliance is null on a plain pdf render — no ruleset was applied, so
there is no claim. Its presence is how you tell a hybrid PDF from an ordinary
one.
It is read back from the record, not recomputed, so
GET /api/v1/renders/{render_id} answers with the version the document was
actually checked against rather than whatever the rulesets say today. fully_checked
means here exactly what it means above: false says the authoritative tier did
not run for the file you shipped.
advisories are the non-fatal findings the render proceeded past. An empty list
means nothing was raised.
Which call do I want?¶
| Question | Call |
|---|---|
| Will this be accepted, before I commit to anything? | POST /documents/validate-compliance |
| I need the XML to hand to my access point | POST /documents/xml or GET /documents/{id}/xml |
| I need one file to email that satisfies Factur-X | any render with format: "facturx_pdf" |
| What was this file held to? | compliance on the render |