EN
Get API keyGet key

Validate an invoice against EN 16931 in one request

Point one POST at your invoice XML and get back a verdict against EN 16931 plus the country rules layered on top. Here is the whole loop, and how to read the result.

Validation is the cheapest check you can run before an invoice leaves your system. One request tells you whether the file is structurally sound, semantically correct against EN 16931, and compliant with the country rules that apply to it.

The request

Send the XML as the request body. You do not have to declare the syntax or the country profile; Beliq detects them from the document.

Request
curl -X POST https://api.beliq.eu/v1/validate \
  -H "Authorization: Bearer $BELIQ_KEY" \
  -H "Content-Type: application/xml" \
  --data-binary @invoice-INV-2026-00481.xml

The same endpoint takes a hybrid PDF. Send Content-Type: application/pdf and Beliq pulls the embedded invoice XML out of the attachment before validating it.

Reading the response

A 200 means the request was processed, not that the invoice passed. The verdict and the per-rule detail come back in the JSON body, wrapped in a success / data envelope.

Response · 200
{
  "success": true,
  "data": {
    "valid": true,
    "verified": true,
    "format": "ubl",
    "profileDetected": "xrechnung",
    "schematronVersion": "1.3.16",
    "ciusVersion": "XRechnung-2.6.0",
    "sha256": "e3b0c44298fc1c14…",
    "rulesetSha256": "7d865e959b2466…",
    "rulesetArtifacts": [
      { "key": "en16931_ubl_schematron", "version": "1.3.16", "fileSha256": "…" },
      { "key": "xrechnung_schematron", "version": "2.6.0", "fileSha256": "…" },
      { "key": "xrechnung_severity_overrides", "version": "2026-08-31", "fileSha256": "…" }
    ],
    "errors": [],
    "warnings": []
  }
}

Here the document was UBL, the country layer was detected as XRechnung, and valid is true with no errors. Read valid together with verified: a false on both means no rule set ran, which is a different situation from a document that ran and failed.

schematronVersion and ciusVersion name the rule versions in human terms. sha256 fingerprints the exact bytes that were validated, so you can prove later which file earned the verdict.

Proving which rules judged you

rulesetArtifacts is the part worth wiring into your own records. It lists every rule artifact that actually executed, each with its version and the SHA-256 of its exact bytes. rulesetSha256 is the combined fingerprint over that set, and you can rebuild it yourself: sort the <key>@<version>=<fileSha256> lines and hash them.

That turns “it passed” into something you can defend. The document fingerprint says which file was checked, the artifact list says which rules checked it, and both came back in the same response.

Each entry in errors and warnings carries a ruleId, a severity (fatal, error, warning or info), a human-readable message, and usually a location pointing into the document. That is what you render in a UI or attach to a ticket.

Pinning the rules on purpose

By default a request is judged against the latest rule set, which moves when an authority publishes a new one. If you would rather decide when that happens, send a Beliq-Ruleset header: either a channel (latest or previous), or exact per-format pins such as xrechnung_schematron:2.5.0. The ruleset that actually applied comes back in the Beliq-Ruleset-Resolved response header, which is also how you spot a fallback from previous to latest when a pin you asked for has been retired.

GET /v1/rulesets publishes the channels you can select and the versions behind them, so a pin in your build config can be checked against what is live.

Where to go next

The full response schema, including the per-country fields a French, Italian or Spanish document adds, lives in the API reference.

EN 16931ValidationCI

Build against the real rulesets.

Generate, validate, and parse e-invoices through one API. Free tier, no card.