Audit

Export audit logs (CSV or JSON)

Exports audit logs as a downloadable file. Filters mirror /api/v1/audit/search (same ILIKE user/client matching, canonical action expansion, JSONB policy filters and date range), so an export always reconciles with the on-screen search for the same filters. Tenant scope is forced from the X-Tenant-ID header.

The export is capped at 50,000 rows; when the cap is hit the response carries the X-Audit-Export-Truncated: true and X-Audit-Export-Row-Cap headers so callers can warn that the file is partial. Free-text CSV cells are formula-escaped (leading =, +, -, @, tab or CR is prefixed with ') to neutralize spreadsheet formula injection.

post/api/v1/audit/export

Request

Query parameters

format'csv' | 'json'

Export format. Defaults to json.

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.

Request body

user_emailstring

Case-insensitive partial (ILIKE substring) match

client_idstring

Case-insensitive partial (ILIKE substring) match

actionstring

Canonical verdict filter (allowed, blocked, redacted, needs_approval, error); expanded to all historical DB spellings of that verdict.

session_idstring

Exact match on the first-class session_id column

decision_idstring

Matches policy_details->>'decision_id'

policy_namestring

Same three-shape policy_details match as /api/v1/audit/search

override_idstring

Matches policy_details->>'override_id'

start_timestring date-time
end_timestring date-time

Response

Export file (Content-Disposition attachment). CSV columns, in order: id, timestamp, user_email, tenant_id, org_id, policy_decision, request_type, query, response_sample, provider, model, response_time_ms, tokens, correlation_id, session_id.

response_time_ms is EMPTY for a row whose writer measured nothing (#3424), never 0: a spreadsheet skips an empty cell in AVERAGE() and would otherwise let every unmeasured row vote that average towards zero.

countinteger

Number of entries in this export

truncatedboolean

True when the row cap was hit

row_capinteger

Example response

{
  "row_cap": 50000
}

Changes

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