Audit Log Export
This is the operator guide for exporting the audit ledger to a file. It covers the async endpoint contract, the shape of the exported rows, how authorization and redaction work, and how to consume the result. For what the ledger captures and the live filters, see Audit Log.What the export ships
There are two export paths, and they ship different row shapes. Read this before parsing a file:- Synchronous quick export (
GET /settings/audit-logs/export) — curated six-column shape:timestamp,user,action,resource,resource_id,ip_address. Internal hash-chain columns, organization/tenant ids, raw user ids, and user-agent are deliberately projected out, so the file is what a reviewer actually needs and nothing more. Capped at 10,000 rows. The response schema validates each row explicitly rather than treating it as a free-form object. - Async export (this page) — streams the row set the underlying ledger keeps, in one of three formats:
json(one JSON object per entry, all ledger fields includingid,organization_id,tenant_id,user_id,action,resource,resource_id,details,ip_address,user_agent,current_hash,created_at),csv(same fields, RFC 4180 escaped), orscim(RFC 8417 Security Event Tokens, the envelope SIEM pipelines ingest directly). No row cap below the 1M-row hard ceiling.
json for a BI/SQL lifter, csv for spreadsheet review, scim when the downstream is a log drain that speaks Security Event Tokens. Both json and scim arrive as one JSON array; csv arrives as a header plus escaped lines.
Async export endpoint
Use the async path when the ledger exceeds the quick export’s 10,000-row cap, or when the download is part of a compliance pull that must not truncate.POST /api/v1/settings/audit-logs/export-async accepts a JSON body:
It returns
202 immediately with the new job’s id:
GET /api/v1/settings/audit-logs/export-jobs/{job_id}. The job moves pending → running → complete, and on complete the response’s gcs_url carries the signed download URL. Download with a plain GET — no API key needed on the URL itself (treat it as a secret; do not paste it into chat or tickets). GET /api/v1/settings/audit-logs/export-jobs lists your org’s recent jobs newest-first, cursor-paginated by createdAt so you can page back through past runs.
Authorization and redaction
Export endpoints are owner/admin only — the same gate the dashboard’s Audit Log page enforces. API-key authentication uses a key created by an owner or admin; dashboard Bearer tokens pass when the session role clears the gate. The sync export’s curated projection is itself a redaction control: the internal tamper-checksum columns, the rawuser_id, and user_agent never leave the platform on that path. For the async export, the raw ledger fields listed above are shipped intentionally — a DSAR or an audit reviewer needs the full record, and the file lands behind a signed URL only the requester receives. Scope your download handling accordingly: hold the URL as a secret, and delete the downloaded copy under your own archival policy (see Immutable Archival Export for the retention/retrieval split).
Jobs are scoped to the requesting organization: GET a job id that another organization queued and you get a 404, not the job. Re-queuing an export does not leak prior generations’ URLs — each job mints its own signed URL.
Consuming the export — worked example
The most common downstream is a BI or SQL tool. Thejson format is the cleanest lifter — one object per entry, every field named and primitive except details (a nested JSON object for before/after payloads).
pd.read_json('audit-export.json') → one row per ledger entry, details explodable with df.join(pd.json_normalize(df['details']))), DuckDB (SELECT * FROM read_json_auto('audit-export.json')), or a Google Sheet import after converting to CSV. For a pull into a SIEM pipeline, request format: "scim" once and hand the file to your log drain’s file-watcher — each array element is a complete Security Event Token the drain can ingest without transformation.
When you need exactly the on-screen filter set narrowed to a small window rather than the whole ledger, prefer the synchronous quick export endpoint instead — its curated six columns tend to be what a reviewer actually wants from a focused pull.
Limits
- Rate — enqueue and quick-export endpoints are limited to 5 requests per minute per organization. Rapid duplicates return
429; a queued job is cheap to leave pending, so queue once and poll. - Row ceiling — the async path hard-caps at 1,000,000 rows (many years of typical ledger volume). The quick export caps at 10,000 rows and flags truncation rather than silently handing you a partial file (
truncated: truein the envelope, plus anX-Export-Truncated: trueresponse header). - Signed URL lifetime — the download URL is valid for 24 hours. Polls that arrive after expiry report the job as
expiredwith no URL; re-queue to mint a fresh one. - Date window — pick
24h/7d/30d/90dfor bounded reviews,allonly for a full-ledger pull (a GDPR DSAR or an annual evidence sweep). The smaller the window, the faster the job completes. - Large exports — page by narrowing
date_rangeand splitting into per-week or per-month jobs rather than oneallpull. Each job page-fetches the ledger in 1,000-row batches server-side, so splitting a huge range across N jobs costs the platform no more than one big job and gives you N smaller, resumable downloads.