Verification
Verify a receipt Built
A receipt is the whole point. Anyone you hand one to can check it, with no account, and without taking our word for anything.
The check
curl -sS https://<your-box>/v1/verify \
-H "content-type: application/json" \
-d '{ "receipt": <the receipt>, "payload_hash": "<sha256 of salt + payload>" }'The salt is in the receipt, so the hash is sha256(payload_salt || your original bytes).
The endpoint will not accept your payload, only its hash. A hosted verifier that received payloads would be a hosted copy of everyone's evidence. You hash locally and send 32 bytes.
What comes back
The answer is valid, tampered or unknown, and it always lists what it has proven beside what it has not proven. Read the second list. It is the honest part, and it does not get shorter when someone important is watching.
| Typically proven | Typically not |
|---|---|
| The payload hash matches the sealed bytes | That the statement inside the record was true |
| The chain is continuous across this record | That the named actor personally authorised it |
| The batch signature is valid under a published key | Anything outside the coverage window it reports |
| The head is published, and anchored once Bitcoin confirms | An anchor that has not landed yet, which it says plainly |
Without running our code at all
You can verify with openssl and nothing else. The signing key is published at a URL the box cannot rewrite, so no enTrail software has to be trusted, or even present. The cryptography is standard throughout: SHA-256, Ed25519, RFC 8785 canonical JSON, and the RFC 6962 Merkle tree, with golden test vectors published so an independent implementation can prove itself correct.
Proofs beyond one record
- Inclusion proof: this record is in the tree that head commits to.
- Consistency proof: a later tree is an append-only extension of an earlier one, so nothing was rewritten in between. This is the one that matters in an argument.
Anchoring takes time, on purpose
A head is offered to the OpenTimestamps calendars after an hour and anchored once Bitcoin confirms. So a receipt fetched minutes after sealing correctly says it is not anchored yet, and later says otherwise with no action from you. Every record is anchored eventually, and the receipt always says which state it is in.
The wait is what makes the time bound worth anything. An anchor gives a Bitcoin block rather than a wall-clock time, so the honest sentence is that this head existed no later than that block.
If verification fails
A tampered answer names what did not match. The usual cause is not an attack: it is bytes that changed on the way to the hash, such as a payload re-serialised by a client library before you hashed it. Hash exactly the bytes you sent. If they genuinely differ from what was sealed, that is what the product is for.
unknown means the receipt refers to something this endpoint cannot see, usually a different box or a record outside the coverage window it reports.
The limits of all of this are set out on the trust model, and we would rather you read it before you rely on anything here.