logs:read. The base URL, bearer authentication, and the error envelope are on the REST API overview; lua logs export is the same surface from a terminal.
Exports are switched on for a deployment as a whole. While they are off, both routes answer
404 — the resource does not exist rather than being forbidden. It may not be enabled on your deployment yet.Scopes
logs:manage is sensitive: a wildcard such as logs:* does not satisfy it. It is checked when the job is started, not when it is read — the decision is frozen onto the job at that moment, because the worker picks the job up minutes later with no request and no principal behind it. A job started without content cannot be upgraded; start another.
Both routes share the drain rate-limit buckets: log-drains-mutate on the start, log-drains-read on the poll.
POST /admin/orgs/:orgId/logs/export
Starts an export. Returns immediately; the work happens on the platform.string
required
Inclusive lower bound: an ISO 8601 instant, or a relative form such as
15m, 2h, or 7d. A relative form is resolved by the server’s clock.string
required
Inclusive upper bound; the same formats.
string[]
Up to 200 agent ids. Defaults to every agent in the organization.
string[]
Any of
production, sandbox. Defaults to both.boolean
default:"false"
Include
user_message and agent_response bodies. Requires logs:manage.202 with { "jobId": "lex_…", "state": "queued", "createdAt": "…" }. Poll the status route.
Errors
Only the eighteen execution-log sources and
execution are exportable. The six adjacent-record sources — delivery, trigger-execution, job-execution, workflow-run, voice-call, and workflow-audit — are built for a drain out of the platform’s own ledgers and are not execution-log rows, so there is nothing for an export to read. Naming one answers 422 EXPORT_SOURCE_UNSUPPORTED. To capture them, point a drain at a destination you can read.GET /admin/orgs/:orgId/logs/export/:jobId
Reads one job. A job id belonging to another organization answers404, never 403 — the two cases are deliberately indistinguishable.
Response
Errors
Caps
One export runs per organization at a time. That is a guarantee, not a race — a second start answers
409 EXPORT_ALREADY_RUNNING. lua logs export turns that into an attach: a second invocation in a terminal follows the running job to its files rather than refusing.
A truncated export is a success. The files are valid and complete as far as they go; they simply do not cover the whole window. Narrow the window or the sources and run it again.
What the files contain
One complete batch per line. Not one record per line. A record has no resource of its own —service.name, lua.org.id, deployment.environment.name, and the agent version all live on the batch’s resource half. A file of bare records would validate against nothing you were given and would drop the tenancy every record depends on.
Parts are named org-<orgId>-logs-<NNNN>.ndjson.gz, zero-padded so lexical order is emission order:
Validate it against the published schema
Each line is one batch and validates against the same JSON Schema a drain delivery does — byte-identical shape, same encoder.attributes key is carried through rather than rejected — additions are additive within a major version, and a schema addition should never fail a load.
What is not in them
- Rows written before organization attribution existed. A row that never recorded an organization cannot be attributed to one, so it is in no org-scoped export. These are the oldest rows only, and the boundary is fixed: nothing written since carries the gap.
log-type rows with no source. A row the platform never classified is counted incounts.scannedand not incounts.rows.- Message bodies, unless the job was started with
logs:manageandincludeContent: true. The record still arrives, carryinglua.content.withheld: true. - Anything the scrubber caught. Scrubbing is unconditional: there is no flag that skips it, and
includeContent: truedoes not weaken it. An export applies the built-in rule classes (builtin,lua-token,vendor-key); organization scrub rules live on a drain, so they do not apply here.
Retention bounds what you can export
The platform keeps execution logs for 90 days by default. An export can only read what is still there, so a window whose lower bound is older than the retention horizon returns the part of it that survives, not an error. Export before you need to, not after.The CSV download is deprecated
GET /admin/orgs/:orgId/logs/download still works and still caps at 10,000 rows. It is deprecated in favour of this job:
Nothing about the CSV route has changed. Its removal will be its own change, with its own release note.
See also
lua logs export— the same job from a terminal, with the parts downloaded for you- Ship logs to your stack — the streaming half, for everything that happens next
- Object storage — a continuous archive into a bucket you own
- Event schema — every field on every line
- Log drains REST — the drain routes, which share this error envelope

