eliDocs
E-invoicing answers

How do you prove an e-invoice was validated?

Keep the validation response. A useful one carries a fingerprint of the exact bytes and of the rules that judged them, reproducible on your machine years later.

Most validation tools hand you a verdict and nothing else. Months later, when someone questions an invoice, a verdict is worth very little: it does not say which file was judged, and it does not say which version of the rules judged it. Proving validation means keeping evidence you can re-check without asking anyone.

Why a verdict alone is not evidence

Why a verdict alone is not evidence

“This invoice was validated in March” is a claim resting on two unstated assumptions: that the tool judged the exact file you have in your records, and that it judged it against the rules it says it used. Neither is observable from a stored valid: true. If the file was re-encoded in transit, or the tool quietly upgraded its rulebook, the stored verdict still reads the same.

Both assumptions can be turned into something checkable, and the mechanism is ordinary hashing.

Two fingerprints

Two fingerprints

A hash is a short fingerprint of some bytes. The same bytes always produce the same fingerprint, any change at all produces a completely different one, and you cannot work backwards from the fingerprint to the data. That last property is why a hash is safe to store in a ledger, print in an audit file, or email to a counterparty.

A Beliq validation response carries two:

  • sha256 is the fingerprint of the exact request body that was validated. Run sha256sum on your own copy of the file. If it matches, the verdict applies to your precise bytes, with no truncation, re-encoding or substitution in between.
  • rulesetSha256 is a single fingerprint of the whole set of rule artifacts that judged the document, and rulesetArtifacts lists the components it was built from, each with its key, version and own file hash.
Three checks, all on your side

Three checks, all on your side

  1. Confirm the file. Hash your invoice locally and compare it to sha256.
  2. Reproduce the ruleset fingerprint. Format each artifact row as key@version=fileSha256, sort the lines, join them with newlines and hash the result. It equals rulesetSha256. This is deterministic, so the same document and the same pinned rules always give the same value.
  3. Cross-check against the public catalog. The keyless GET /v1/rulesets endpoint lists every artifact that can run, with the same versions and hashes. Each component in your response should appear there byte for byte, which is what turns “these are the rules Beliq says it used” into “these are the rules Beliq publishes to everyone”.

Steps one and two need nothing but the response and the standard hashing tools already on your machine. Step three is one unauthenticated HTTP call that costs no quota. None of it requires Beliq to still be online, or to vouch for anything after the fact.

What this proves, and where it stops

What this proves, and where it stops

Being precise about the ceiling matters more here than a stronger claim would.

For the national formats validated against a published schema (Italy, Spain, Slovenia, Poland), the pinned artifact is the root schema the engine loads. Slovenia’s is a byte-for-byte copy of the authority’s file, so you can reproduce its fingerprint straight from the authority’s download. Italy’s, Spain’s and Poland’s are local copies with a rewritten import, so their fingerprints differ from the authority’s download; Verify a hash says how to repeat the rewrite for Italy and Spain.

For the EN 16931 Schematron families, the pinned artifact is a compiled XSLT. CEN’s, KoSIT’s, FNFE-MPE’s and the NPa’s are vendored as published, so each fingerprint matches the file in the release it came from. The Peppol BIS Billing 3.0 XSLT is compiled by Beliq from OpenPeppol’s published rule sources, so its fingerprint is not something you can reproduce by hashing the authority’s raw source file yourself. Either way the fingerprint proves the artifact Beliq ran is the one Beliq pins and re-verifies. That is the honest boundary: the ruleset that judged you is transparent, self-consistent and tied to a value published for everyone, and for the Peppol BIS XSLT it is not a chain of custody back to OpenPeppol’s own bytes.

Freshness is a separate question

Freshness is a separate question

A pin proves stability, which is exactly what you want in an audit trail and exactly not what you want if the authority quietly republished the rules last week. So a response can also carry driftCheckedAt: not a hash but a timestamp, reporting when the artifacts that judged your document were last confirmed to still match their upstream sources. Read it as a lower bound, “confirmed at least this recently”. It is omitted rather than guessed when that confirmation is not current, so it is never falsely fresh.

What you actually store

What you actually store

Store the validation response next to the invoice, in whatever your records already are. It is small, it contains no invoice content beyond a hash, and it is the artifact that lets you answer, years later and without a support ticket, both halves of the question: this exact file, judged by these exact rules.

Related