OpenReceipt protocol
The OpenReceipt protocol is an open spec — read the canonical version at signedreceipts.org/spec. This page summarises how CloakAPI implements it.
Two envelopes in production
CloakAPI issues two envelope kinds today, depending on the way you use:
- v3 (client-signed) — on the client-side ways (browser chat, desktop app,
browser extension), the device that performed the tokenisation signs an
OpenReceipt v3 envelope (
v: "v3",alg: "ecdsa-p256-sha256") before egress, carrying thev3-attestationclaim set (what egressed, which detector categories fired, engine hashes, trust tier). When the request goes through the gateway, the gateway verifies the client signature and adds an additive countersignature witnessing provider, model, and upstream byte hashes. See the v3 specification for the normative format. - v2 (gateway-signed) — on the bare-SDK API way (
api.cloakapi.io), the gateway seals every response with the v2 flat envelope described below.
v2 envelope shape
The v2 envelope is a flat JSON object signed with ES256 (ECDSA P-256 over SHA-256), canonicalised per RFC 8785 (JCS), and chain-linked per tenant.
{ "v": 2, "alg": "ES256", "kid": "cloakapi-gateway-receipt-2026-q3-es256", "iss": "https://api.cloakapi.io", "jti": "9f1c2b7a4e8d4f0a8c3b2d1e6f7a0b9c", "iat": 1759420800, "timestamp": "2026-04-18T12:00:00.000Z", "request_id": "req_01HWRK9GTBF3MXQJ4VZPND", "provider": "openai", "model": "gpt-4o", "input_tokens": 184, "output_tokens": 312, "hash_upstream_request": "sha256:b3a…", "hash_upstream_response": "sha256:c91…", "chain": { "chain_id": "receipt-v2-org-42", "seq": 47, "prev_hash": "sha256:a3f8c2…" }, "signature": "BASE64URL_RAW_R_S_ECDSA_SIGNATURE"}| Field | Meaning |
|---|---|
v | Protocol version. Integer 2 for the gateway-signed flat envelope (client-signed receipts use string "v3"). |
alg | Signing algorithm. "ES256" (ECDSA P-256 over SHA-256). |
kid | Key id — look up the matching key in the public JWKS to get the verifying key. |
iss | Issuer URL (https://api.cloakapi.io). |
jti | Unique receipt id (128-bit random hex). |
iat | Unix-seconds timestamp the gateway sealed the response. |
timestamp | RFC 3339 timestamp with millisecond precision, always UTC (Z). |
provider / model | Upstream provider slug and model the call was routed to. |
input_tokens / output_tokens | Token counts billed for the call. |
hash_upstream_request / hash_upstream_response | SHA-256 of the on-the-wire bytes — never the bytes themselves. |
chain.chain_id | Per-tenant chain identifier (receipt-v2-org-<org_id>). |
chain.seq | Monotonically increasing per-tenant sequence number. |
chain.prev_hash | Hash of the previous receipt’s canonical bytes (same chain). Lets auditors detect missing or out-of-order receipts. |
signature | URL-safe base64 (unpadded) raw r‖s (64-byte) ECDSA signature over the JCS-canonical bytes of the envelope with signature removed. |
Where to find the public key
- JWKS:
https://api.cloakapi.io/api/.well-known/cloakapi-receipt-pubkeys.jwks - PEM:
https://api.cloakapi.io/api/.well-known/cloakapi-receipt-pubkey.pem
Keys rotate quarterly. Old keys remain in the JWKS so historic receipts keep verifying indefinitely.