What a receipt contains
How the chain works
- The receipt’s fields are serialized in a fixed canonical order.
this_hash = sha256(canonical_receipt || prev_hash)— each receipt’s hash incorporates the previous receipt’s hash.this_hashis signed with the gateway’s ED25519 key.
Chaining and signing happen in an asynchronous writer, off the response path. Receipts
add zero latency to your LLM requests, and the chain only advances after the
receipt is durably stored.
Where to see receipts
- INGRESS — click any request in the live stream to open its receipt drawer (with
RECEIPT | TRACEtabs). - EVIDENCE — chain statistics and a sample verified receipt.
Query and export
GET /v1/receipts takes optional, AND-combined filters — from/to (RFC3339), actor, provider, model, check (a check name present on the receipt), and upstreamStatus — composed with cursor pagination:
GET /v1/receipts/export returns the matched set as a file:
limit (max 50,000); the X-Wardin-Truncated response header is true when more rows matched — narrow the filters or page GET /v1/receipts. Unlike any log tool’s export, the JSONL rows carry the ED25519 signature + hash-chain fields per row.
For full offline chain verification, use the Evidence
Bundle
instead — it carries a contiguous signed segment plus the signing-key registry
and trust anchor that verification requires. A filtered receipt export has
seq gaps (its prev_hash links point at excluded rows) and omits the public
keys, so it’s for querying/analysis, not standalone chain verification.These endpoints query what’s currently retained — the 7–30 day hot analytics
window. They are not a durable audit trail until the WORM cold tier ships
(see below); the same API will front the cold tier when it does. For control-scoped
queries (“all receipts proving
eu_ai_act:art_12”), use Framework
Coverage — GET /v1/compliance/coverage/{framework}/controls/{controlId}/receipts.GET /v1/receipts, GET /v1/receipts/export.
Verifying programmatically
verified: true means the stored hash equals sha256(canonical || prev_hash) and the ED25519 signature over that hash is valid. Receipts are tenant-scoped — you can only read your own.
Full endpoint references (continued): GET /v1/receipts/{id}, GET /v1/receipts/_/verify-chain.
Export an Evidence Bundle (verify offline, no account)
The verification above trusts us to run the check. For an auditor who shouldn’t have to, export a self-contained Evidence Bundle and verify it entirely offline — no Wardin account, no network:- a contiguous signed receipt segment for the window (bounded so the chain has no gaps),
- the signing-key registry for every key the receipts reference — so verification survives key rotation without contacting Wardin,
- the compliance packs in force (framework + version + content hash), and
- a trust anchor for the first link.
wardin-verify recomputes each sha256(canonical || prev_hash), checks the ED25519 signature against the bundled public key for its key_id, and reports any tampered field, broken link, missing key, or seq gap — exiting non-zero if anything fails. It shares the exact canonical-serialization code the gateway signs with. See Offline Verification for the tool’s status, the full bundle-format spec, and the verification algorithm (so you — or an auditor — can reimplement the check in any language).
See the full endpoint reference: GET /v1/compliance/evidence-bundle — the range parameter and the bundle schema.
A bundle covers the receipts currently in the hot analytics window (typically the
last 7–30 days) — it’s an offline-verifiable snapshot of the recent chain, not a
long-term archive. Durable WORM retention that lets a bundle span years is in active
development (see below).
Verify your first receipt
Commissioning — the guided first-run flow — already shows you your first receipt once your first governed request completes; this is how to confirm it yourself, and how to check any receipt afterward:- Open INGRESS and click the row for your first request (or any request) — the
receipt drawer opens with
RECEIPT | TRACEtabs. - The
RECEIPTtab shows aVERIFIED ✓orUNVERIFIED ✕badge.VERIFIEDmeans Wardin recomputedsha256(canonical || prev_hash)from the stored fields and confirmed the ED25519 signature over it matches — nothing is taken on trust. - To verify programmatically instead, fetch the same receipt by ID (see above) and
check its
verifiedfield, or runverify-chainover a range that includes it.
VERIFIED badge happens on every fetch,
independent of who’s watching.
Why this matters for compliance
Frameworks like the EU AI Act and NIST AI RMF ask for evidence that governance controls actually ran — not a dashboard screenshot. A hash-chained, signed record of every enforcement decision (including blocks: over-budget 429s, allowlist 403s, guardrail rejections) is exactly that artifact. Today you can verify any receipt — or a contiguous range of the chain — through the API above: recompute the hash and check the ED25519 signature, nothing taken on trust. Receipts are retained in the hot analytics window (configurable, typically the last 7–30 days).Framework-mapped evidence packs — control-ID citations per check, with a coverage map
and per-control receipt drill-down — ship today as draft mappings; see Framework
Coverage. The one-click auditor Evidence Bundle export
and the offline verifier (spec published; reference CLI, public release in
preparation — check the chain without a Wardin account) are available now, over the
recent window (above). Long-term WORM retention — so a bundle can span years, not
just the hot window — is still in development. Until it ships, treat receipts and
bundles as verifiable runtime evidence over the recent 7–30 day window, not a long-term
archive.