Runtime
Decision audit logs
A receipt for every answer your production agent was served: the route, a digest of the query, the corpus version that answered, and a sha256 of the response bytes. Months later, what the agent knew has an answer you can recompute.
LIVE
Send X-PIT-Audit: on with a Desk key. Nothing to
provision before a run and nothing to turn off after it, because
receipting is per request.
- REST
- X-PIT-Audit: on
- Desk
- json · jsonl
The artifact
One audited call, and the receipt it wrote
An audited request against a local server on 2026-08-27, hashed
on the client with shasum, then the receipt the
server wrote for that same request. The client computes one hash
over the bytes it received and the server computed the other over
the bytes it sent.
$ curl -s -H "Authorization: Bearer pit_live_..." -H 'X-PIT-Audit: on' \
'https://api.pit.aqx.llc/v1/news?ticker=SIVB&as_of=2023-03-10T23:59:59Z&limit=2' \
| shasum -a 256
c45adddabc2821c015847211159cdbc6d7bd3ea63fb2723e20b4aa39ad9a35cf -
{
"ts": "2026-08-27T18:58:31.817Z",
"key_id": "key_84887c96e987ca3712993c8a073a7a6a",
"route": "GET /v1/news",
"params_digest": "701c3eae4f1dbcfaf5147f12dc07d0526f40680265498eb1ef170d0770317851",
"corpus_version": "sha256:29336a245255fdc7be9b5b0b1a6e90053e958a78a58166dbefeaeedce05eea7a",
"envelope_sha256": "c45adddabc2821c015847211159cdbc6d7bd3ea63fb2723e20b4aa39ad9a35cf",
"request_id": "014f795d-67fb-4c97-a9dd-d8c1a97eb4c6"
}
envelope_sha256 is the hash above.
request_id is the X-Request-Id that came
back on the response, so a receipt and a support question point at
the same call. params_digest is reproducible from the
query string alone, and the recipe is on the
reference page.
The failure it prevents
Reconstructing what the agent knew, months later
A customer, a regulator or your own postmortem asks what the agent was looking at when it acted. Application logs record what your code did, and they rarely record which version of the record answered it in a form somebody outside your team can check.
A hash over the exact bytes
envelope_sha256 covers the response body as you
received it, trailing newline included, so anyone holding that
response can recompute it in one command.
The corpus that answered
corpus_version is the content hash of the record at
the moment of the answer, so a later backfill cannot quietly
rewrite what the agent was shown.
Refusals are receipted
A 409 for a coverage hole is something the agent was shown, so it gets a receipt with its own digest and its own request id, the same as an answer.
How it works
Hashed on the way out, written after you have your answer
Receipting is switched on per request
X-PIT-Audit: on turns it on for one call.
1, true and yes work too,
and the header name is case-insensitive. A backtest that wants
receipts sends the header, and the same key's interactive
queries stay out of the table. Nothing is provisioned before a run
and nothing has to be switched off after it.
A request without the header costs one path-prefix test and one header lookup, benchmarked at 19 ns with no allocations on an Apple M4 Pro. Writing a receipt costs about 2.2 µs, and none of that is a database round trip: the write happens after the response has gone.
The row holds hashes, never a body
| Field | What it records |
|---|---|
ts | When the response finished, RFC3339 UTC to the millisecond. |
key_id | The key that asked, which is the id GET /v1/keys lists. |
route | Method and path. The query string is not in it. |
params_digest | sha256 of the canonical query string, 64 hex, always present. |
corpus_version | The X-Corpus-Version of that response. |
envelope_sha256 | sha256 of the response body bytes. |
request_id | The X-Request-Id, tying a receipt to a server log line. |
The table has no body column under any name, and a test fails if one appears. Storing the values would mean keeping a copy of every answer your agent ever read, where storing the digest lets you show that the copy you kept yourself is the right one.
Loss is counted and published
Receipts are written after the response has gone, on a drain goroutine behind a bounded queue 1200 deep, which is one full minute of a Desk key's rate limit. A full queue drops rather than making the response wait, so a database stall shorter than a minute costs nothing.
Every audited response carries
X-PIT-Audit-Dropped, the running process drop count. A
caller who watches that number stay still knows the log has no
hole. GET /v1/audit-log/stats publishes the whole
tally, including lost, which adds dropped to failed:
a write that returned an error counts as loss rather than as a
success.
Integration
One header out, one route back
$ curl -s -H "Authorization: Bearer pit_live_..." \ 'https://api.pit.aqx.llc/v1/audit-log?day=2026-08-27&limit=100' $ curl -s -H "Authorization: Bearer pit_live_..." \ 'https://api.pit.aqx.llc/v1/audit-log?format=jsonl&day=2026-08-27&limit=1000' \ > receipts-2026-08-27.jsonl
Receipts are owner-scoped and ordered by the instant they were
served. The log is append-only, so a page you already read never
changes and resuming a cursor gives you only newer entries.
format=jsonl serves
application/x-ndjson, one receipt per line, with the
next token in X-PIT-Audit-Next-Cursor.
What is not receipted, and the gaps we know about
| Case | Why |
|---|---|
No X-PIT-Audit header | Opt-in. The request never enters the path. |
Paths outside /v1/ | /health, the site, POST /t. |
| A key not on Desk | Counted under plan_required. |
| A browser session, or a key we rejected | A receipt records a key id, and there is none. Counted under unattributed. |
| Replies that are not JSON | The OpenAPI document, an SSE stream, a 304. Counted under skipped. |
| Reading the log | Reading the receipts would write receipts, which would need reading. |
-
MCP tool calls are not receipted.
The MCP endpoint forwards
AuthorizationandX-Forwarded-Foronto the request it builds, and not the audit header. - Retention is 400 days, an annual audit cycle plus a quarter. There is no retention job yet, so rows are kept until one is written.
- The two routes are not in the OpenAPI document yet.
Related
What sits either side of it
Downstream
Contamination Certificates
A signed verdict on one evaluation run, for when a hash of your own is not enough.