Verifying a Jithox receipt offline
Tool executions on the Jithox MCP fleet are signed. This page shows how anyone verifies one of those signatures without contacting us at verification time, what a valid signature proves, and what it does not.
The short answer
The public key does not travel inside the receipt you are checking. It is published at a separate endpoint, and that distinction is the whole point: a key shipped in the same payload you are trying to verify anchors nothing, because anyone who can rewrite the payload can rewrite the key next to it. You fetch the key once over a channel you already trust, and from then on verification is a local computation.
Algorithm: Ed25519, detached signature over a canonicalised payload.
The four public artefacts
- Verification contract
- The active key set, the algorithm, the canonicalisation rules per receipt version, and the rotation policy — machine-readable, in one document.
- Public key (PEM)
- The key that signs today's receipts. Any specific key is also retrievable by its id.
- Standalone verifier
- Node, built-in modules only, no dependencies. It opens no sockets — verification works air-gapped.
- A signed sample
- A real receipt, so you can prove the verifier accepts a good one and rejects a tampered one before trusting either.
Verify one in four commands
curl -sS -O https://mcp.jithox.com/receipts/sample.json
curl -sS -O https://mcp.jithox.com/receipts/public-key.pem
curl -sS -O https://mcp.jithox.com/receipts/verify-receipt.mjs
node verify-receipt.mjs sample.json public-key.pem
# VALIDA check that never rejects anything proves nothing, so flip a single character of resultHash:
node verify-receipt.mjs tampered.json public-key.pem
# INVALID (signature does not match payload)Where your own receipt lives
The complete signed receipt comes back in the tool result's _meta.receipt — every signed field plus the signature. Write it to a file and the verifier above accepts it directly. The Trust envelope additionally carries a receiptEnvelope naming the receipt version, the canonicalisation version, the algorithm, the key id, the exact signed payload, the signature, and the URLs for the public key and this contract — so you no longer have to know where to look.
The key identifies itself
The key id is derived from the key: a SHA-256 of its SPKI. The verifier recomputes it from the PEM you hand it and refuses the receipt when it does not match. You therefore cannot be talked into verifying against the wrong key, and we cannot silently swap keys underneath a receipt.
Three canonicalisations, domain-separated
Each receipt version has its own context string, so the versions cannot be confused with one another. Relabelling a v2 receipt as v3 does not produce a v3 receipt — it produces a failure. That fails closed rather than quietly passing, and it is tested rather than assumed.
Rotation
Each key has a unique id. On rotation the new key is added to the verification contract and previous public keys stay listed for at least 24 months. Receipts are never re-signed and never rewritten, so an old receipt keeps verifying against the key that signed it.
What a valid signature means
This exact receipt payload was produced by the Jithox signing key at issuance time and has not been altered since.
What it does not mean
- It is not a legal, fiscal or compliance guarantee.
- It is not proof that an underlying VAT or VIES answer is still current — a registry result is true at the moment it was fetched, and nothing more.
- It is not proof of payment beyond the referenced rail record.
- It does not vouch for the correctness of an upstream authority's data.
- There is no endpoint that hands you a past receipt by its id. Keep the receipt when you receive it — we do not hand it back later.
Related
Trust and controlled execution — the mechanisms and their limits. Invalid, invalid input, or VIES unavailable — what a VAT check actually returns.