Audit

Get a single audit entry by ID

Returns the full audit entry for the given id, tenant-scoped by the X-Tenant-ID header. A record that exists but belongs to another tenant returns 404 (not 403), so the endpoint cannot be used as a cross-tenant existence oracle. Literal /api/v1/audit/* routes (search, export, report, session-summary, tenant, tool-call) are matched before this parameterized path — including GET /api/v1/audit/search, which answers 405 rather than being swallowed here as an id of "search" (#3060).

Role-scoped reads (#2922): a non-tenant-wide caller may fetch only their own rows; a record belonging to another user returns the same 404 as a missing one (non-oracle). See POST /api/v1/audit/search for the deployment-mode carve-outs.

get/api/v1/audit/{id}

Request

Path parameters

idstring required

Audit entry id

Headers

X-Tenant-IDstring required

Tenant identifier scoping the request. The AxonFlow Agent gateway sets this header after authentication; the orchestrator fails closed when it is absent (401 on audit/decision endpoints, 400 on others — see each operation). Clients cannot widen their scope through it: handlers force the tenant filter from this header, never from the request body.

Response

Full audit entry

idstring
request_idstring
timestampstring date-time
user_idinteger
user_emailstring
user_rolestring
client_idstring
tenant_idstring
org_idstring
request_typestring
querystring

The audited query/prompt (already redacted by the write path)

query_hashstring
policy_decisionstring

Verdict for the request. Canonical values are allowed, blocked, redacted, needs_approval, error; historical rows may carry legacy spellings.

policy_detailsobject

Nested decision detail exactly as the writer stored it (policy_ids / reasons / latency_ms plus writer-specific keys like gateway_id, tool_name, decision_id, override_id, policy_matches). Treat keys as writer-specific.

providerstring
modelstring

LLM model identifier the request was routed to (e.g. gpt-4o-mini, llama3.2:latest). Surfaced separately from provider so callers can filter audit reads by model without parsing the provider's vendor-specific naming.

response_time_msinteger

Measured duration for this row in whole milliseconds. ABSENT when this row's writer measured nothing (#3424).

Absent is NOT 0. This field used to be emitted unconditionally, so every row from a writer with no duration to record -- blocked request / response / media, failed request, workflow, plan and tool-call rows, HITL approvals, and the connector-exec MCP closure -- carried a literal 0, which the portal's Latency column rendered as a confident "0ms". The key is now omitted for those rows rather than set to null: this schema declares no required list, so the property was already optional and a conforming client already handles its absence. Nothing about the declared contract changes.

A 0 that DOES arrive is a real measurement: the column is whole milliseconds, so a decision the platform timed at under 1ms is stored as the 0 its clock produced. The portal renders that as "<1ms" and an absent value as "-".

The quantity differs by plane: enforcement duration on decision/gateway/mcp/openai_compat, a PROVIDER round trip on llm, and a client-asserted OTLP duration on cowork/claude_code (#3431). The compliance summary's avg_latency_ms averages only the first.

tokens_usedinteger

Provider tokens consumed by this request, OMITTED when the row carries no RECORDED provider usage (#3427). The omission says the usage was not recorded; it does NOT assert that no provider was called. Two distinct populations omit it:

  • Rows whose writer never reached a model at all -- a blocked request, a redaction, a gateway pre-check deny, a media deny, a workflow step, a plan or a tool-call row.
  • Rows written by the LLM RESPONSE-plane block writer, which runs AFTER the forward: the call was made and the answer was withheld, so a real round trip was paid for, but that writer records none of the provider usage it is handed. That is a gap in the writer, tracked separately, not a claim about the request.

Until #3427 both populations left the read paths as a literal 0, which the portal's detail panel rendered as "Tokens 0" under a request no model saw. The key is now omitted for those rows rather than set to null: this schema declares no required list, so the property was already optional and a conforming client already handles its absence. A 0 that DOES arrive is a real report from a provider, not an absence.

costnumber double

Estimated provider cost for this request in USD, OMITTED when the row carries no recorded provider usage (#3427). Same rule, same two populations and same rationale as tokens_used above; note that 0 is a genuinely representable cost (a locally hosted or free-tier model), which is why absence is expressed by omitting the key rather than by a zero.

redacted_fieldsstring[]
error_messagestring

Omitted when empty

response_samplestring
compliance_flagsstring[]
security_metricsobject
decision_idstring

Canonical decision-row id (#2597/ADR-058); present on planes that mint decisions, omitted on legacy writers

planestring

Enforcement plane that wrote the row (e.g. mcp, llm); omitted on legacy writers. The orchestrator's four ENFORCEMENT planes are orchestrator_request for /api/v1/process and /api/v1/plan/execute, wcp for the workflow step gate, map for a multi-agent step and orchestrator_response for the LLM response. (policy_simulation and policy_test are the orchestrator's too, but they are operator tools rather than enforcement points and write no decision row.)

correlation_idstring

Decision-chain correlation key (#2611); omitted when not stitched

transfer_basisstring

UU PDP Pasal 56 cross-border transfer legal basis (adequacy, safeguards, pasal_56b_dpa, consent) — Enterprise LLM-forward path only (#2718)

data_residencystring

ISO 3166-1 alpha-2 destination country (#2718); Enterprise only

session_idstring

AI-tool session id (Claude Code / Desktop) forwarded via X-Session-Id; asserted attribution, not an auth boundary

Changes

No recorded changes to this operation across all 1 revision of this API.