Audit API
2 endpoints. Request and response schemas are described on the schemas page; the other tags are listed in the API index.
Endpoints
GET /api/v1/admin/audit
List audit entries
List audit log entries, newest first (admin only). Two paging modes: offset paging (page/per_page, the default) and keyset paging (cursor). Keyset paging never counts rows or scans past an offset, so it stays fast on large tables; follow next_cursor while has_more is true. In offset mode total is exact when total_exact is true (small tables and the last page); otherwise it is the planner's row estimate (no filter) or a lower bound (with actor/action filters).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | no | 1-based page number (offset paging). Ignored when cursor is present. Minimum: 1. |
per_page | query | integer | no | Minimum: 1. Maximum: 100. |
cursor | query | string | no | Opaque next_cursor of the previous page. Present but empty starts keyset paging at the newest entry. Selects keyset paging: the response carries no page, total or total_exact. |
actor | query | string | no | Case-insensitive substring of the actor name or actor id. |
action | query | string | no | Case-insensitive substring of the action name. |
Responses
| Status | Description | Body |
|---|---|---|
200 | Paginated list of audit entries | application/json: object |
400 | Malformed cursor | - |
403 | Admin access required | - |
Fields of the 200 response (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
data | array of AuditEntry | no | - |
has_more | boolean | no | True when entries follow this page. |
next_cursor | string | no | Pass as cursor to fetch the next page. Absent when has_more is false. |
page | integer | no | Offset paging only. |
per_page | integer | no | - |
total | integer | no | Offset paging only. See total_exact. |
total_exact | boolean | no | Offset paging only. False when total is an estimate or a lower bound. |
GET /api/v1/admin/audit/export
Export audit log
Export the audit log as JSONL or CSV (admin only). Streams the log as a download without counting rows: entries are read in keyset pages (newest first) and flushed after every page, so memory stays bounded however long the log is. The body is chunked (no Content-Length); if the server fails after the response started the connection is aborted rather than ended normally, so a truncated file is detectable. In CSV, cells starting with =, +, -, @, tab or CR are prefixed with ' to defuse spreadsheet formula injection. Fields (stable; new fields may be appended): id, timestamp (RFC 3339, UTC), action, actor, actor_type, actor_id, resource_type, resource_id, repository_id, project_id, ip, details (JSON object; in CSV its JSON text). Unset values are null in JSONL and empty in CSV.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
format | query | string | no | jsonl (default): one JSON object per line. csv: header row plus one record per entry. One of: jsonl, csv. Default: jsonl. |
since | query | string | no | Only entries at or after this instant: RFC 3339 timestamp or YYYY-MM-DD (00:00 UTC). |
until | query | string | no | Only entries strictly before this instant (same forms as since); must be after since. |
actor | query | string | no | Case-insensitive substring of the actor name or actor id. |
action | query | string | no | Case-insensitive substring of the action name. |
Responses
| Status | Description | Body |
|---|---|---|
200 | Audit export stream Headers: Content-Disposition. | application/x-ndjson: string; text/csv: string |
400 | Unknown format, malformed since/until, or since not before until | - |
403 | Admin access required | - |