Skip to content
einvoicing.dev

API/Validation

Validate a Peppol document

POST/v1/validations· API key

Validates a Peppol BIS Billing 3.0 invoice or credit note in three layers, in order: the UBL 2.1 schema (xsd), the EN 16931 rules (en16931) and the Peppol rules (peppol). A layer that cannot run because an earlier one failed is reported as skipped, not passed.

Every finding carries the official rule text verbatim, a plain-English explanation, the business terms it concerns and, where one exists, a concrete fix.

Send the document either as raw XML (application/xml, convenient from curl) or wrapped in JSON (application/json, which is what an agent's tool call can carry). Both are validated identically.

A document that breaks the rules is a successful validation: the response is 200 with valid: false. Nothing is stored.

Request
curl -X POST https://api.einvoicing.dev/v1/validations \  -H "Authorization: Bearer $EINVOICING_API_KEY" \  -H "Content-Type: application/xml" \  --data-binary @invoice.xml

Parameters

NameInTypeDescription
rulesetquerystring

Pin validation to a specific ruleset id from GET /v1/rulesets. Omit it to use the ruleset whose status is current.

Request body

application/xmlapplication/json· required

Example bodyapplication/xml
<?xml version="1.0" encoding="UTF-8"?><Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"         xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"         xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">  <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>  <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>  <cbc:ID>INV-2026-0042</cbc:ID>  <cbc:IssueDate>2026-09-11</cbc:IssueDate>  <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>  <cbc:DocumentCurrencyCode>GBP</cbc:DocumentCurrencyCode>  <!-- parties, tax total, monetary totals and lines omitted for brevity --></Invoice>

Response

200

The document was validated. Check valid: true means no finding has severity error; warnings may still be present.

FieldTypeDescription
datarequiredValidationReportThe outcome of validating one document.
Example responseapplication/json
{  "data": {    "valid": false,    "ruleset": {      "id": "peppol-bis-billing-3.0.21",      "version": "3.0.21"    },    "document": {      "type": "invoice",      "customization_id": "urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0",      "profile_id": "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"    },    "layers": [      {        "name": "xsd",        "status": "passed"      },      {        "name": "en16931",        "status": "passed"      },      {        "name": "peppol",        "status": "failed"      }    ],    "summary": {      "errors": 1,      "warnings": 0    },    "findings": [      {        "rule_id": "PEPPOL-EN16931-R003",        "layer": "peppol",        "severity": "error",        "message": "A buyer reference or purchase order reference MUST be provided.",        "explanation": "Peppol needs something the buyer can use to route the invoice internally. Neither a buyer reference (BT-10) nor a purchase order reference (BT-13) was present.",        "fix": "Add the buyer's purchase order number as `cac:OrderReference/cbc:ID`, or their reference as `cbc:BuyerReference`.",        "business_terms": [          "BT-10",          "BT-13"        ],        "location": {          "xpath": "/Invoice",          "line": 2,          "path": null        },        "docs_url": "https://www.einvoicing.dev/rules/PEPPOL-EN16931-R003"      }    ]  }}

Errors

Every error is application/problem+json (RFC 9457). Branch on type, which is stable, never on title or detail.

StatusWhen
400

The body could not be parsed as the XML or JSON its Content-Type declares. Distinct from 422, which means the body parsed and its contents were rejected. Problem type is malformed-body.

/problems/malformed-body

401

No key, or a key that is unknown or revoked. Problem type is unauthenticated.

/problems/unauthenticated

402

The Free plan's monthly allowance for this operation is used up. This is a billing state, not a rate limit: waiting will not help until the period resets or the plan changes. Paid plans never receive it. Problem type is allowance-exhausted.

/problems/allowance-exhausted

413

The body is larger than 5 MiB. Problem type is payload-too-large.

/problems/payload-too-large

415

The Content-Type is not one this operation accepts. Problem type is unsupported-media-type.

422

The body is well-formed but not a document this API validates: the root is not a UBL Invoice or CreditNote, the CustomizationID is not one a supported ruleset covers, or the requested ruleset does not exist. Problem type is unsupported-document or unknown-ruleset.

429

Too many requests in a short window. Slow down and retry after the number of seconds in Retry-After. Problem type is rate-limited.

/problems/rate-limited

503

The validator could not judge the document. The fault is on our side, not in the document, and nothing was stored. It is never reported as valid or invalid. Retry after the number of seconds in Retry-After. Problem type is validator-unavailable.

/problems/validator-unavailable

Schemas

ValidateDocumentRequest

A Peppol document wrapped in JSON, for clients that can only send JSON.

FieldTypeDescription
documentrequiredstringThe complete UBL 2.1 Invoice or CreditNote XML, as a string.

ValidationReport

The outcome of validating one document.

FieldTypeDescription
validrequiredbooleanTrue when no finding has severity error.
rulesetrequiredRulesetRefThe ruleset a report was produced against.
documentrequiredobjectWhat the document declared itself to be.
typerequiredstringFrom the document's root element.

invoicecredit_note

customization_idrequiredstring or nullThe document's cbc:CustomizationID (BT-24), or null if absent.
profile_idrequiredstring or nullThe document's cbc:ProfileID (BT-23), or null if absent.
layersrequiredobject[]Each validation layer in the order it runs.
namerequiredstringxsd is the UBL 2.1 schema, en16931 the European standard's rules, peppol the Peppol BIS Billing 3.0 rules.

xsden16931peppol

statusrequiredstringskipped means an earlier layer failed, so this one could not run meaningfully.

passedfailedskipped

summaryrequiredobject
errorsrequiredintegerNumber of findings with severity error.
warningsrequiredintegerNumber of findings with severity warning.
findingsrequiredFinding[]Every finding, errors first, then in document order.