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.
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.
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.
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.
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")
// npm install jose
import { createRemoteJWKSet, jwtVerify } from "jose";
const API = "https://api.tresor.co";
const TOKEN = "YOUR_API_KEY";
const jwks = createRemoteJWKSet(new URL(`${API}/.well-known/jwks.json`));
const { receipt } = await fetch(
`${API}/v1/receipts/7c9e6679-7425-40de-944b-e07fc1f90ae7`,
{
headers: { Authorization: `Bearer ${TOKEN}` },
},
).then((r) => r.json());
const { payload } = await jwtVerify(receipt, jwks, { algorithms: ["ES256"] });
console.log("Receipt verified:", 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.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.