Reference
Decision audit logs
Send X-PIT-Audit: on with a Desk key to record every /v1 response. Each entry records the timestamp, the API key, the route, a query digest, the corpus version, and the SHA-256 hash of the response bytes. The system does not store the response body.
Reference page. Updated 2026-08-27. Desk plan only.
Turning it on
X-PIT-Audit: on. You can also use 1, true, or yes. Header names are case-insensitive.If a request does not include the header, the server checks only the header and does not look up the key.
What a receipt holds
| Field | What it is |
|---|---|
ts | When the response finished. RFC3339 UTC with a literal Z, to the millisecond. |
key_id | The API key that asked. The same id GET /v1/keys lists. |
route | Method and path, such as GET /v1/news. The query string is not here. |
params_digest | SHA-256 of the query string in a canonical form, 64 hex characters. Two calls asking the same thing match; the values themselves are not stored. |
corpus_version | The corpus that answered, from the X-Corpus-Version header. JSON null when the call was refused before a corpus was consulted. |
envelope_sha256 | SHA-256 of the response body, byte for byte as you received it. |
request_id | The X-Request-Id of that response, so a receipt and a support question point at the same call. |
A query against a given corpus_version returns the same data every time because the corpus is content-addressed. The envelope hash still differs between two identical queries because every response carries its own request_id. This makes the hash a receipt that proves which exact bytes one caller received.
Checking a receipt
Hash your response bytes with SHA-256 and compare the result to
envelope_sha256. Include the trailing newline, which
curl passes through by default.
$ 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
The resulting hex string matches envelope_sha256 in
the receipt. Refused calls are also logged. For example, a 409
response for a coverage hole produces a receipt with a null
corpus_version because no corpus answered the
request.
Reproducing params_digest
To calculate params_digest: parse the query string,
sort each parameter's values, sort the parameters by name, and
re-encode them as percent-encoded k=v pairs joined by
&. Then compute the SHA-256 hash of that string.
If a request has no query string, hash the empty string.
import hashlib, urllib.parse
def params_digest(query):
pairs = urllib.parse.parse_qs(query, keep_blank_values=True)
canon = urllib.parse.urlencode(
sorted((k, v) for k, vs in pairs.items() for v in sorted(vs)))
return hashlib.sha256(canon.encode()).hexdigest()
params_digest("ticker=SIVB&as_of=2023-03-10T23:59:59Z&limit=2")
is
701c3eae4f1dbcfaf5147f12dc07d0526f40680265498eb1ef170d0770317851.
Reading your log
$ curl -s -H "Authorization: Bearer pit_live_..." \
'https://api.pit.aqx.llc/v1/audit-log?day=2026-08-27&limit=100'
The response uses the standard envelope
with one receipt per item in results. Receipts are
scoped to your account.
| Parameter | What it does |
|---|---|
day | One UTC calendar day, YYYY-MM-DD. Omit for every day. |
limit | 1 to 1000, default 100. A value outside that range returns 400. |
cursor | next_cursor from the previous page. Send the same day with it. |
format | json (default) or jsonl. |
Pages are ordered chronologically by ts. The log is
append-only, so existing pages never change. When you resume
pagination, you receive only newer entries.
Exporting
Use format=jsonl to receive raw
application/x-ndjson with one receipt per line and no
outer envelope. If more pages exist, the next token is in the
X-PIT-Audit-Next-Cursor response header.
$ 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
Knowing the log is complete
Receipts are written asynchronously after each response using a fixed-depth queue. If the queue is full, the server drops the receipt so the request is not delayed. Dropped receipts are counted and exposed in two places.
The X-PIT-Audit-Dropped header is included on all
audited responses and all /v1/audit-log responses. It
shows the total number of receipts the server process has dropped
since startup. If the value does not change during a run, no
receipts were lost.
$ curl -s -H "Authorization: Bearer pit_live_..." \
https://api.pit.aqx.llc/v1/audit-log/stats
| Field | What it counts |
|---|---|
receipts | Receipts stored for your account. day_receipts is the same count for a day you name. |
lost | Receipts owed and not held: queue.dropped plus queue.failed. |
queue.requested | Calls that asked to be receipted. |
queue.unattributed | Asked, but had no valid API key, so there was no key to record. |
queue.plan_required | Asked with a key that is not on Desk. |
queue.skipped | Asked, but the response was not a JSON envelope. |
queue.enqueued | Accepted into the queue. written reached the database, failed did not. |
queue.dropped | Refused because the queue was full. |
queue.queued | Waiting right now, out of capacity. |
The queue metrics cover the entire server process
rather than a single key, because dropped receipts are not
attributed to a key ID. The default queue depth is 1200, which
holds one full minute of requests at the Desk rate limit.
What is not recorded
| Case | Why |
|---|---|
No X-PIT-Audit header | Receipting is per request. |
Paths outside /v1 | Only /v1 routes are receipted. /health, the website and POST /t sit outside. |
| A key on another plan | Counted under plan_required. |
| A rejected key or a browser session | Counted under unattributed: a receipt records a key id, and there is none to record. |
| Replies that are not JSON | The OpenAPI document, the /v1/stream event stream, a 304 whose body you already hold. Counted under skipped. |
| Reading the log itself | Excluded so that reading the log does not add to it. |
| MCP tool calls | The /mcp endpoint does not pass the header through yet. |
Retention
The retention policy for Desk receipts is 400 days. This limit is
currently not enforced, and receipts are kept indefinitely. Use
format=jsonl to export and store receipts long term.
Limits
/v1/audit-log and /v1/audit-log/stats
allow 60 requests per minute per account. This limit is separate
from the standard /v1 limit on your plan. Requests
above this limit return a 429 status code with a
Retry-After header.
These two routes are not yet in openapi.json, so
generated SDK clients do not include them. You must call them
directly. The dashboard does not display
receipts.