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.
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.xmlThe 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.
{
"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.