Runs
One id, one lifecycle — track it, download what it produced, keep it or let it expire.
Every capability call creates a run. The id tells you what it is — exr_ extract, par_ parse, rdr_ redact, flr_ fill, sgr_ sign, plr_ pipeline — and one set of routes works across all of them.
Track a run
GET /v1/runs/:id returns the same body the original call returns, and takes the same ?wait= (0–120 seconds) — long-poll instead of hammering it. ?include=evidence is accepted and does nothing: citations are always included when the run was grounded.
A plr_ pipeline additionally carries steps[], each with its own id, status, and output.
List runs
GET /v1/runs returns your organization’s runs, newest first — the one call that answers “what is still in flight?” without a run id in hand.
List entries are handles, not results — no output, no config. Fetch GET /v1/runs/:id for the data.
Paging is cursor-based: pass the response’s cursor back as ?cursor= until has_more is false. Pages don’t overlap, and a cursor is opaque — don’t parse or construct one.
Filter by your own metadata
Every capability call takes a metadata object, and it is the intended join key between your system and ours:
Tag every run at creation with the ids you already have — a job id, a customer id, an invoice number — and you never need to store our run ids to find your work again.
GET /v1/runs is in the SDKs as of 0.3.0 — client.runs.listRuns({ object, status, limit, cursor }) in TypeScript, client.runs.list_runs(object=…, status=…, limit=…, cursor=…) in Python. The metadata.<key> filters aren’t typed parameters; send those over HTTP as shown above.
The list is eventually consistent. A run created moments ago can be missing from GET /v1/runs, or show a status one step behind. GET /v1/runs/:id is always authoritative — never decide “finished” or “failed” from the list, and never treat an absent run as a lost one.
Cancel and purge
Cancelling an already-terminal run is a no-op that returns the current body. DELETE is idempotent — purging an already-purged run still returns 204.
Download a produced file
Runs that make a document — a redacted PDF, a filled form, a sealed contract — expose it two ways. The signed URL is inline on the run body at output.file.url, and this route is the stable, guessable alias:
:name is the file name as reported in output.files[].name, or the file id. The response is a 302 to a signed, time-limited URL — follow redirects.
A produced file is registered a moment after the run reports processed. In that window output.file can arrive without its url and this route can answer 404 not_found — re-fetch GET /v1/runs/:id and the URL will be there.
Expiry and TTL
Runs clean themselves up. ttl on the create call (seconds, default 24 hours, max 7 days) sets when the run, its inline-created input files, and its outputs are purged; expiresAt on the run body tells you when.
After expiry, GET /v1/runs/:id answers 410 run_expired for a grace window and then 404 not_found. Persist anything you need before then — or keep it.
Two exceptions:
- Files you registered with
POST /v1/filesare persistent and are never purged by a run’s TTL. - Sign runs are TTL-exempt. An envelope must outlive the 7-day maximum, so a
sgr_run — and a pipeline containing asignstep — is not purged while the envelope is open.expiresAtis still present on the body; for a sign run it is not enforced.
Keep a run
keep is the bridge from the headless API into the CloudRaker product. It moves the run’s files and outputs into a real space, re-indexes them for search and the knowledge graph, imports extraction results as records when the action was bound to a data object, and clears the run’s TTL.
Send either {"space": {"name": "…"}} to create a space or {"spaceId": "…"} to use an existing one — sending both is a 400.
dashboardUrl opens the space in the app: this is the link you put in your own UI when a human needs to look at what the API produced. Afterwards GET /v1/runs/:id reports expiresAt: null — the run is no longer on a clock.
Keeping the same run into the same space again is a no-op; keeping it into a different space returns 409 already_kept. Keeping a run that hasn’t finished returns 409 pipeline_running — wait for a terminal status first.
Everything a /v1 run touches is invisible in the app until you keep it. That is what makes ephemeral-by-default safe: nothing accumulates in your organization’s spaces unless you ask for it.
Human tasks
A run at needs_input is waiting on a person:
- Fill — the run body carries
tasks: [{id, title, url}]. Eachurlis a hosted review page you can open or hand to a reviewer; the same task is also readable and submittable over/v1/runs/:id/taskif you would rather build your own UI. - Sign — no
tasks[]: signing links are signer-held secrets. The run body carriesenvelopeUrlinstead, and the envelope is tracked and managed with/v1/runs/:id/envelope,/void,/audit, and/signers/:id/resend.
On a pipeline these sub-routes resolve to the matching step — /task* to the fill step, the rest to the sign step — and 404 when the pipeline has no such step.