Client area

Docs

Async jobs

Some operations cannot finish inside the call that starts them. Those hand back a job id you poll, instead of holding a connection open.

The job handle

An operation that cannot finish inside its own request returns a small handle instead of a result: {jobId, kind, status, pollWith}. pollWith is always "get_job" — it names the tool to call next, so a model never has to construct a path or guess at a convention.

Over REST the same handle is polled at GET /jobs/{jobId}. Job ids look like job_ followed by 26 characters. Never invent one — an id you were not handed is a job_not_found.

Polling a job

Polling returns the full row: jobId, kind, status, progress, meta, result, error, isTerminal, createdAt and resolvedAt. Stop when isTerminal is true; that is the one field to branch on, and it saves you enumerating the terminal states yourself.

progress is an integer from 0 to 100, or null when the operation does not report one. It is a hint for a progress bar, not a schedule.

Reading a job requires read:account, and a job belonging to another account is a job_not_found rather than a denial. The poll only ever reads a row — it never performs or advances the work — so it is safe to call on a loop. Poll every few seconds and respect the rate limit: a polling loop is still traffic.

Job states

  • queued — accepted, not started.
  • running — in flight, with progress when the operation reports it.
  • succeededresult is populated, progress is 100.
  • failederror is populated.
  • cancelled — stopped before it finished; neither result nor error.

The last three are terminal: isTerminal is true, resolvedAt is stamped, and nothing more happens to the row.

When a job fails

A failed job's error is a {code, message} object describing what went wrong inside the work. It is not the Problem Details envelope — that envelope belongs to the HTTP call, and the poll that reports a failed job is itself a perfectly successful 200. Check status, not the status code.

Esc
navigate open Esc close