Skip to content

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

Header
Set X-PIT-Audit: on. You can also use 1, true, or yes. Header names are case-insensitive.
Plan
Requires a Desk plan. Requests using a Researcher or Power key work normally, but the system does not record them.
Scope
Send the header on each request you want to log. No other configuration is needed for a Desk key.

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

FieldWhat it is
tsWhen the response finished. RFC3339 UTC with a literal Z, to the millisecond.
key_idThe API key that asked. The same id GET /v1/keys lists.
routeMethod and path, such as GET /v1/news. The query string is not here.
params_digestSHA-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_versionThe corpus that answered, from the X-Corpus-Version header. JSON null when the call was refused before a corpus was consulted.
envelope_sha256SHA-256 of the response body, byte for byte as you received it.
request_idThe 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.

terminal

$ 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.

python

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

terminal 200 · newest last

$ 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.

ParameterWhat it does
dayOne UTC calendar day, YYYY-MM-DD. Omit for every day.
limit1 to 1000, default 100. A value outside that range returns 400.
cursornext_cursor from the previous page. Send the same day with it.
formatjson (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.

terminal

$ 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.

terminal

$ curl -s -H "Authorization: Bearer pit_live_..." \
    https://api.pit.aqx.llc/v1/audit-log/stats
FieldWhat it counts
receiptsReceipts stored for your account. day_receipts is the same count for a day you name.
lostReceipts owed and not held: queue.dropped plus queue.failed.
queue.requestedCalls that asked to be receipted.
queue.unattributedAsked, but had no valid API key, so there was no key to record.
queue.plan_requiredAsked with a key that is not on Desk.
queue.skippedAsked, but the response was not a JSON envelope.
queue.enqueuedAccepted into the queue. written reached the database, failed did not.
queue.droppedRefused because the queue was full.
queue.queuedWaiting 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

CaseWhy
No X-PIT-Audit headerReceipting is per request.
Paths outside /v1Only /v1 routes are receipted. /health, the website and POST /t sit outside.
A key on another planCounted under plan_required.
A rejected key or a browser sessionCounted under unattributed: a receipt records a key id, and there is none to record.
Replies that are not JSONThe OpenAPI document, the /v1/stream event stream, a 304 whose body you already hold. Counted under skipped.
Reading the log itselfExcluded so that reading the log does not add to it.
MCP tool callsThe /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.