The authorization receipt format
An authorization receipt (formerly Trust Receipt) is a signed, offline-verifiable record that a specific action was authorized — by whom, under what policy, with what outcome. Anyone with the signer’s public key can verify one with no account, no API, no network. This page specifies it precisely enough to implement a verifier in any language.
1. Document
anchor is optional; @version, payload, and signature are required.
{
"@version": "EP-RECEIPT-v1",
"payload": { ... the signed claim ... },
"signature": { "algorithm": "ed25519", "value": "<base64url>" },
"anchor": { // OPTIONAL
"leaf_hash": "<hex sha-256>",
"merkle_proof": [ { "hash": "<hex>", "position": "left|right" } ],
"merkle_root": "<hex>"
}
}2. Payload
The payload is application-defined; the signature covers it whole. EP’s convention:
{
"receipt_id": "ep_...",
"issued_at": "2026-06-04T00:00:00Z",
"claim": {
"action": "payment.release",
"outcome": "allow | allow_with_signoff | deny",
"approver": "operator:<named human>",
"context": { "amount": 50000, "destination": "acct_9f12", "currency": "USD" }
}
}3. Canonicalization
The exact bytes that get signed. Recursive, depth-first key sort at every level — byte-identical on signer and verifier for any nesting depth. A shallow sort is not sufficient; nested keys must be ordered too.
object -> "{" + keys.sort().map(k => json(k) ":" canon(v[k])).join(",") + "}"
array -> "[" + elements.map(canon).join(",") + "]"
scalar -> JSON encoding (UTF-8; non-ASCII NOT escaped)4. Signature
Algorithm Ed25519, over canonicalize(payload) as UTF-8 bytes. The public key is the base64url of its SPKI DER encoding; signature.value is the base64url of the 64-byte signature.
5. Merkle anchor (optional)
leaf_hash is a hex SHA-256. Each proof step folds the running hash with a sibling: sorted([a, b]) then SHA-256(lo ‖ hi) (hex); position: "left" means the sibling is on the left. The reconstructed value must equal merkle_root. Proof length is bounded (≤ 20).
6. Verification algorithm
@version∈ {EP-RECEIPT-v1}, else invalid.- Ed25519-verify
signature.valueovercanonicalize(payload)with the signer’s key. - If
anchoris present, reconstruct the root fromleaf_hash+merkle_proof; it must equalmerkle_root. - Valid iff version holds, signature verifies, and (anchor absent OR anchor reconstructs). A malformed receipt verifies as invalid — never raises.
7. Reference implementations
Interop is tested: a receipt signed on the JS side verifies under the Python implementation, and vice versa.