Verify a receipt

Fetch and cryptographically verify the JWS receipt issued for a chat completion.

Every chat completion returns a receipt_id you can later trade in for a JWS-signed receipt. This guide shows the end-to-end flow: get the id, fetch the receipt response, then verify the signature against the router's public JWKS.

For the underlying data model — payload fields, signing algorithm, signing-key rotation — see Concepts → Receipts.

1. Get the receipt id

Receipts are issued by default on every completion. The id appears in the response body's tresor extension (or the finish chunk for streams):

curl https://api.tresor.co/v1/chat/completions \
  -H "Authorization: Bearer $TRESOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-oss-120b",
    "messages": [{"role": "user", "content": "Hello!"}]
  }' | jq '.tresor.receipt_id'
"7c9e6679-7425-40de-944b-e07fc1f90ae7"

To opt out of receipt issuance for a specific request, send X-Tresor-Receipt: false.

2. Fetch the receipt response

Trade the id for the full signed receipt at any time:

curl https://api.tresor.co/v1/receipts/7c9e6679-7425-40de-944b-e07fc1f90ae7 \
  -H "Authorization: Bearer $TRESOR_API_KEY"
{
  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "receipt": "eyJhbGciOiJFUzI1NiJ9.eyJzY2hlbWEuLi4..."
}

→ Endpoint reference: GET /v1/receipts/{id}

The receipt field is the compact JWS. If you use tresor-verify, you can pass the entire JSON response directly; no jq wrapper is required.

3. Verify with tresor-verify (easiest)

curl -s https://api.tresor.co/v1/receipts/7c9e6679-7425-40de-944b-e07fc1f90ae7 \
  -H "Authorization: Bearer $TRESOR_API_KEY" \
  | tresor-verify receipt \
      --jwks-url https://api.tresor.co/.well-known/jwks.json \
      -
PASS
Receipt type:  message
Key ID:        router-receipt-1

If you already saved the API response to disk, point tresor-verify receipt at that JSON file directly.

4. Verify the JWS signature manually

Fetch the JWKS from /.well-known/jwks.json and verify with any ES256-capable library.

# pip install pyjwt[crypto] requests
import json, jwt, requests
from jwt.algorithms import ECAlgorithm

API = "https://api.tresor.co"
TOKEN = "YOUR_API_KEY"

jwks = requests.get(f"{API}/.well-known/jwks.json").json()

receipt_jws = requests.get(
    f"{API}/v1/receipts/7c9e6679-7425-40de-944b-e07fc1f90ae7",
    headers={"Authorization": f"Bearer {TOKEN}"},
).json()["receipt"]

for key_data in jwks["keys"]:
    try:
        public_key = ECAlgorithm.from_jwk(key_data)
        payload = jwt.decode(receipt_jws, public_key, algorithms=["ES256"])
        print("Receipt verified:", json.dumps(payload, indent=2))
        break
    except jwt.InvalidSignatureError:
        continue
else:
    raise SystemExit("No JWKS key matched the receipt signature")

5. (Optional) Validate the payload

Once the signature checks out, validate the claims your policy actually cares about:

  • jti should match the receipt_id you fetched.
  • requested_route should match the normalized route you asked the router to use.
  • routed_model should match the fully resolved route you expected the router to use.
  • If requested_route and routed_model differ while failover is false, that usually means automatic route resolution selected a concrete route without needing failover.
  • request_digest and response_digest bind the signed receipt to the exact exchange.
  • router_attestation captures the Tresor router TEE evidence recorded at issuance time.
  • inference_attestation captures the upstream inference TEE evidence recorded at issuance time.
  • receipt_signature records the receipt-signing key context at issuance; it is not a live key-validity probe.

Older receipts may label the upstream hop provider_attestation instead.

For stronger release binding on the router hop, validate router_attestation.workload_identity_manifest_jws together with router_attestation.workload_identity_tag. When present, trust_bundle_jws and trust_bundle_url let you verify the workload manifest against an offline trust bundle.

The full payload schema is documented under Concepts → Receipts.

See also