Docs · Verify
Three ways to verify a receipt.
A receipt is worth more than the office that issued it. Verification can be performed in your browser, on the command line offline, or by reading directly from the Bitcoin chain with any compatible node. The three paths below are independent; agreement between any two is sufficient for almost any practical purpose, and the third remains available if the office itself is no longer reachable.
The receipt is the instrument. The chain is the trust anchor. Verification does not depend on this office continuing to exist.
1 · Browser verifier
The simplest path, and the one that requires no installation. Paste the receipt identifier into the verifier at /verify-js.html; the page fetches that receipt from the office when you press the button (or you paste the receipt JSON instead, and nothing is fetched), hashes the file you select locally, and reports whether it matches the fingerprint the receipt records. It does not check the OpenTimestamps proof or Bitcoin; run the command-line verifier or any OpenTimestamps client for that. The page and its verifier script can be saved to disk with the browser's complete-page option.
1. open /verify-js.html
2. paste the receipt id (16 hex chars)
3. select the original file
4. browser computes SHA-256, compares it with the
receipt, and reports OK / mismatch
The browser verifier handles single-file receipts only. For folder receipts, use the command-line verifier’s folder subcommand below, which rebuilds the Merkle root from the files in place; see folder anchoring by Merkle root for the algorithm.
2 · Offline command-line verifier
For long-term verification — years after the anchor, on a machine with no network, or in a forensic context where every dependency must be inspected. Standard library only; no pip install step. Published under MIT so the format outlives the office.
curl -O https://orphograph.com/dist/orphograph-verify.zip
unzip orphograph-verify.zip
cd orphograph-verify
# Verify a single file against an inclusion proof:
python3 verify.py file --file path/to/original.jpg \
--proof path/to/proof.json \
--ots path/to/root.ots
The verifier re-hashes the local file, cross-checks against the proof's recorded SHA-256, walks the inclusion proof bottom-up using the RFC 6962 algorithm, and (when --ots is supplied) invokes the OpenTimestamps reference client to confirm the Bitcoin-chain witness. The same script handles folder receipts via a different subcommand:
python3 verify.py folder --dir path/to/folder \
--manifest path/to/manifest.json \
--ots path/to/root.ots
The OpenTimestamps reference client is installable separately:
pip install opentimestamps-client
Developer detail · proof file structure, exit codes
The proof JSON returned by the office (and accepted by the verifier) carries the relative path, the expected root, the file's SHA-256, and the sibling hashes that walk the leaf up to the root. The verifier reads the fields below and ignores any others it does not know. A worked example with placeholder values:
{
"receipt_id": "ChvTMbYLIACHEHJT",
"path": "2026-05-20/IMG_0042.cr3",
"root_hex": "a1b2c3d4e5f6…32 bytes hex…",
"file_sha256_hex": "f3a9d2…32 bytes hex…",
"proof": [
["R", "1111…"],
["L", "2222…"],
["R", "3333…"]
]
}
Exit codes: 0 verified; 2 invalid arguments or a missing/unreadable input; 3 the file, proof, or folder did not reproduce the recorded root; 4 the OpenTimestamps chain step did not pass. Output is plain text, one check per line:
[OK] inclusion proof verifies against root
[OTS] VERIFIED: root.ots: Bitcoin block 800000 attests existence …
[FAIL] local file SHA-256 does not match proof's file_sha256_hex
[OTS] UNAVAILABLE: ots binary not found on PATH — the chain step did NOT run.
On exit 4 the [OTS] line names the state: FAILED means the client rejected the proof; PENDING, UNAVAILABLE, UNBOUND, and INDETERMINATE mean the chain step rendered no verdict, and the file or folder result above it still stands on its own.
The vendored merkle.py module carries a SHA-256 banner in its header; the banner is compared, on each invocation, against the SHA-256 of the file as loaded from disk, so silent drift from the canonical algorithm is detectable.
3 · Directly from the Bitcoin chain
The most independent path. Anyone with a Bitcoin node — full or pruned — can extract the commitment from the recorded block without recourse to the office or to any third-party verifier. The OpenTimestamps reference client provides the standard tooling; the receipt is a self-describing proof file whose terminal step is a Bitcoin transaction in a Bitcoin block.
# Walk the OTS proof to the Bitcoin commitment:
ots verify path/to/root.ots
# Output (placeholder values):
Got 1 attestation(s) from
https://alice.btc.calendar.opentimestamps.org
Got 1 attestation(s) from
https://btc.calendar.catallaxy.com
…
Confirmed. Bitcoin block 949114 attests existence as of
2026-05-12 18:34:43 UTC.
The OpenTimestamps client connects to public calendars or to a local Bitcoin node configured in ~/.ots. With a local node, no third-party service is contacted; the verifier reads block 949114 from the node's own copy of the chain and confirms the commitment is present.
The argument that a Bitcoin block timestamp is admissible evidence is summarized at why a Bitcoin-anchored hash matters.
What each path confirms
- Browser verifier — the file in your hand reproduces the fingerprint recorded in the receipt. The proof itself is left to the next two paths.
- Offline CLI verifier — re-hashes the file and walks its inclusion proof with no network call, on a machine that has never spoken to the office; with
--otsit hands the proof to the OpenTimestamps client, which needs a Bitcoin node for the chain step. - Bitcoin chain directly — the recorded block is part of the canonical chain; the commitment is present in that block; the file's fingerprint walks to that commitment.
The three paths agree when the receipt is genuine. Disagreement of any kind is evidence that the receipt, the file, or the proof has been altered since issuance.
Further reading
Disclaimer. The office anchors the existence of a byte sequence at a recorded time. The office does not certify authorship, truth, originality, or compliance with any external standard, and does not give legal advice. A receipt is a description of what was anchored, not a judgment about what the anchored thing means. A customer with an actual dispute should consult counsel admitted in the relevant jurisdiction.