The audit log as CSV, narrowed by the same filters as the list.
const url = 'https://example.com/api/v1/audit/export.csv';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://example.com/api/v1/audit/export.csv \ --header 'Authorization: Bearer <token>'This is the endpoint that makes Export mean what it says. The button used to write out the rows the browser had scrolled to, which is a different set from “everything matching” — in a log whose purpose is completeness, that is a correctness problem rather than a missing feature. The list endpoint’s filters moved into SQL first; this closes the other half.
before is deliberately not accepted: a cursor is where a page starts, and an export is not
paged. Accepting it would let a caller export “the second page” and believe it was the answer.
The response is a download rather than JSON, so a failure has nowhere useful to render — which is why the filter is validated the same way the list validates it, before anything is fetched.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”Only entries at or after this RFC 3339 timestamp.
Only entries at or before this RFC 3339 timestamp.
Free text matched against the username and the action (case-insensitive substring).
Comma-separated action kinds (post, put, patch, delete, login, mcp); empty or
absent means every kind. An unknown token is rejected rather than ignored.
Comma-separated status classes (ok, client, server); empty or absent means every
class.
Responses
Section titled “Responses”Every matching entry as CSV, newest first, capped
A range bound is not RFC 3339, or action/status is not one of the listed values
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}No valid bearer token
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}Role lacks the view-audit permission
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}Skeleton mode keeps no audit log
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}