Runs

One id, one lifecycle — track it, download what it produced, keep it or let it expire.

View as Markdown

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.

GET /v1/runs list your recent runs
GET /v1/runs/:id status + result
POST /v1/runs/:id/cancel stop in-flight work
DELETE /v1/runs/:id purge now
POST /v1/runs/:id/keep persist into the product
GET /v1/runs/:id/output/:name download a produced file

Track a run

$curl "https://api.cloudraker.com/v1/runs/exr_01KYD1J8QW2RN4T6VXZ0ABCDEF?wait=30" \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY"

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.

StatusMeaning
queuedAccepted, not started yet.
processingReading the documents or running the capability.
processedFinished. output is present.
failedTerminal failure. Per-file causes are on files[].error.
cancelledYou cancelled it.
expiredPast its ttl — the run and its files are gone.
needs_inputWaiting on a human — a fill review or an open signature envelope. Never reached by extract or parse.

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.

$curl -G "https://api.cloudraker.com/v1/runs" \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
> --data-urlencode "object=extract_run" \
> --data-urlencode "status=processed" \
> --data-urlencode "limit=20"
1{
2 "object": "list",
3 "data": [
4 {
5 "object": "extract_run",
6 "id": "exr_01KYDQEEK5413ASVYK21GJ375J",
7 "status": "processed",
8 "createdAt": "2026-07-25T22:48:31.072Z",
9 "expiresAt": "2026-07-26T22:48:30.721Z",
10 "statusUrl": "/v1/runs/exr_01KYDQEEK5413ASVYK21GJ375J",
11 "metadata": { "job": "nightly-backfill" }
12 }
13 ],
14 "has_more": true,
15 "cursor": "MjAyNi0wNy0yNVQyMjo0ODozMS4wNzJa"
16}

List entries are handles, not results — no output, no config. Fetch GET /v1/runs/:id for the data.

ParameterValues
objectextract_run, parse_run, redact_run, fill_run, sign_run, pipeline_run.
statusprocessing, processed, failed, cancelled, expired, needs_input. queued is not accepted here and returns a 400 listing the six values above, even though a run body can report queued. Filter on processing to find work in flight.
limit1–50, default 20. Over 50 is a 400.
cursorThe cursor from the previous page. Omit it for page one.
metadata.<key>Up to three metadata.<key>=<value> pairs, combined with AND. A fourth is a 400.

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:

$curl -G "https://api.cloudraker.com/v1/runs" \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
> --data-urlencode "metadata.job=nightly-backfill" \
> --data-urlencode "metadata.tenant=acme"

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

$# stop work that's still going; files and the TTL are untouched
>curl -X POST https://api.cloudraker.com/v1/runs/exr_…/cancel \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY"
>
># delete the run, its files, and its outputs right now
>curl -X DELETE https://api.cloudraker.com/v1/runs/exr_… \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY"

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:

$curl -L https://api.cloudraker.com/v1/runs/rdr_…/output/"w9 (redacted).pdf" \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
> -o redacted.pdf

: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/files are 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 a sign step — is not purged while the envelope is open. expiresAt is 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.

$curl -X POST https://api.cloudraker.com/v1/runs/exr_01KYD7KC6B…/keep \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{ "space": { "name": "Q3 invoices" } }'
1{
2 "object": "run",
3 "id": "exr_01KYD7KC6B…",
4 "spaceId": "0e441359-1c8a-4f26-9d75-2a2d3c9e7f10",
5 "dashboardUrl": "https://app.cloudraker.com/spaces/0e441359-1c8a-4f26-9d75-2a2d3c9e7f10"
6}

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}]. Each url is a hosted review page you can open or hand to a reviewer; the same task is also readable and submittable over /v1/runs/:id/task if you would rather build your own UI.
  • Sign — no tasks[]: signing links are signer-held secrets. The run body carries envelopeUrl instead, 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.

Next steps