Skip to main content

Why runs exist

The chat endpoints (Messages, Chat Completions, Responses) are stateless — one request, one turn, and the connection is the only place the work lives. An agent loop is not one turn: it is a job that can outlive a socket, be resumed by a different process, and needs an audit trail after it finishes. A run is that job as a first-class object. It has an id, an append-only event log, a terminal outcome, and it is scoped to the key that created it.
Runs, states, and artifacts are one surface. Reach for the chat endpoints when you want a completion; reach for runs when you want a job you can hand off, follow, and inspect afterwards.

Endpoints

Every endpoint authenticates exactly like the rest of the API — Authorization: Bearer lx1_... — and is scoped to the authenticated key. Ids are never a tenancy check on their own: a run belonging to another key returns 404, not someone else’s data.

Create a run

Executable vs. bookkeeping runs

The response status tells you which one you created:
  • 202 Accepted — you sent both model and a usable input, so the gateway is executing the run for you. The body is { "run": { ... }, "execution": "started" }. Follow it on the event stream.
  • 201 Created — no executable payload. The run is a durable record you drive yourself by appending events. The body is { "run": { ... } }.
Executable run
202 Accepted

Idempotency

Send an Idempotency-Key header (up to 200 characters) and a repeat of the same create returns the original response instead of starting a second run. Replays come back with 200 and an idempotency-replayed: true header, and keys are remembered for 24 hours. This is the header to reach for whenever a retry could duplicate real work — a network blip on a submit, an at-least-once queue, a cron that fires twice.
Idempotency is best-effort by design: if the key store is briefly unavailable the create still succeeds rather than failing. Treat it as strong protection against retries, not as a distributed lock.

Read a run

Returns { "run": { ... } }, or 404 when the id does not belong to your key.

Follow the event stream

Server-Sent Events. Each frame carries the event’s own type as the SSE event: name and the full event object as JSON data:. The stream ends with a terminating frame:
An executable run always reaches a terminal outcome event — including when execution throws. A client tailing the stream is never left waiting on a run that died silently.
Tail a run

Append your own events

For runs you drive yourself: record tool calls, checkpoints, and decisions into the same log the gateway writes to, so one timeline covers the whole job.
Request
Response

Cancel a run

The body is optional: { "reason": "superseded by run_456" }. Returns the updated run.

States

A state handle is a durable, append-only value scoped to your key — the place to keep an agent’s working memory when the agent itself is stateless across processes. Each append returns a monotonically increasing seq, so two writers can tell whose write landed last.
Create, append, read
The append path uses a colon, not a slash — /v1/states/{id}:append. That is deliberate: it keeps {id} a clean resource path so a state id can never collide with a sub-resource name.

Errors

This surface returns a flat, protocol-neutral error body:

From the CLI

Every endpoint on this page has a npx layerx1 equivalent — useful for poking at a run without writing a client:
See the CLI reference for the full command list.