The protocols, in copy-pasteable code.
For developers integrating receipts.you into a pipeline. Every snippet is the actual JSON shape, command, or call you'd use — not pseudo-code, not an OpenAPI ref. If something here doesn't reproduce, file an issue.
Seal a hash into a receipt.
Compute the SHA-256 and perceptual hashes locally (image bytes never leave your environment), then POST the JSON envelope below to /api/seal.
POST https://receipts.you/api/seal
Content-Type: application/json
{
"hash": "f1a2b3c4d5...", // 64-char hex SHA-256 of file bytes
"phash": "0123456789abcdef", // 16-char hex pHash (DCT-based)
"dhash": "fedcba9876543210", // 16-char hex dHash (gradient-based)
"stamped_hash": "9876...", // OPTIONAL — hash of QR-stamped composite if you're providing it
"note": "Tweet from @example", // OPTIONAL — short user-supplied note
"source": "https://twitter.com/example/status/123" // OPTIONAL
}
→ 200 OK
{
"id": "abc123xyz456", // 12-char receipt ID
"receipt_url": "https://receipts.you/r/abc123xyz456",
"timestamp": "2026-05-25T14:32:00.000Z",
"signature": "MEUCIQ...", // base64-encoded ECDSA P-256 signature
"anchor_status": "pending" // → "confirmed" after OTS cron (~30 min)
}The privacy-preserving hash path.
Six lines of WebCrypto. The image bytes stay in your browser; only the 64-char hex goes outbound.
async function sha256OfFile(file) {
const buffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
const arr = Array.from(new Uint8Array(hashBuffer));
return arr.map(b => b.toString(16).padStart(2, "0")).join("");
}
const hex = await sha256OfFile(file); // 64-char hex stringSee the deep-dive for why this is the whole privacy story, and how to verify it in DevTools.
Get a verdict for a file against a receipt.
POST https://receipts.you/api/verify
Content-Type: application/json
{
"id": "abc123xyz456", // receipt ID (from the QR or URL)
"hash": "f1a2b3c4d5...", // SHA-256 of file being verified
"phash": "0123456789abcdef", // pHash of same file
"dhash": "fedcba9876543210" // dHash of same file
}
→ 200 OK
{
"verdict": "identical", // or "recompressed" / "similar" / "qr_pasted" / "mismatch"
"phash_distance": 0,
"dhash_distance": 0,
"receipt": {
"id": "abc123xyz456",
"timestamp": "2026-05-25T14:32:00.000Z",
"anchor_status": "confirmed",
"ots_block_height": 851234
}
}Five commands, no service dependency.
# 1. Hash the file openssl dgst -sha256 -hex screenshot.png # → SHA256(screenshot.png) = <64-char hex> (compare to receipt's "hash") # 2. Reconstruct the signed payload echo -n "<hash>:<iso_timestamp>" > payload.txt # 3. Verify ECDSA signature against our public key echo -n "<base64_signature>" | base64 -d > sig.bin openssl dgst -sha256 -verify pubkey.pem -signature sig.bin payload.txt # → Verified OK # 4. Verify the OpenTimestamps anchor pip install opentimestamps-client echo -n "<base64_ots_proof>" | base64 -d > screenshot.png.ots ots verify screenshot.png.ots # → Success! Bitcoin attests data existed as of <date>
See the full walkthrough for context on each command.
Inspect a receipt's anchor state.
GET https://receipts.you/api/ots-status/abc123xyz456
→ 200 OK
{
"id": "abc123xyz456",
"anchor_status": "confirmed", // or "pending"
"ots_upgraded": true,
"ots_block_height": 851234,
"ots_block_time": "2026-05-25T15:02:11Z",
"ots_proof_base64": "AHJv..." // full OpenTimestamps inclusion proof
}Worker liveness.
GET https://receipts.you/healthz
→ 200 OK
{
"status": "ok",
"version": "<commit-sha>",
"ots_cron_last_run": "2026-05-25T14:30:00.000Z",
"rate_limit": { "ip_per_min": 1000, "ip_per_day": 10000 }
}Calibrated to let real usage through.
- 1000 requests per IP per minute
- 10,000 requests per IP per day
- No country-level gating
If you have a use case that legitimately exceeds these, email [email protected] and we'll figure something out. The limits exist to make trivial abuse uneconomic, not to push real users to a paid tier.
What you get back from a receipt page.
Append .json to any receipt URL to get the full machine-readable record:
GET https://receipts.you/r/abc123xyz456.json
{
"id": "abc123xyz456",
"hash": "f1a2b3c4d5...",
"phash": "0123456789abcdef",
"dhash": "fedcba9876543210",
"stamped_hash": "9876...",
"timestamp": "2026-05-25T14:32:00.000Z",
"signature": "MEUCIQ...", // base64 ECDSA P-256
"signer_kid": "v1", // key ID, maps to /.well-known/receipts-pubkey.pem
"anchor": {
"status": "confirmed",
"ots_proof_base64": "AHJv...",
"ots_block_height": 851234
},
"note": "Tweet from @example",
"source": "https://twitter.com/example/status/123"
}