Extract
Turn documents into structured JSON with per-field citations, in one call.
POST /v1/extract takes one or more documents and a JSON Schema, and returns data shaped like your schema — plus a citation for every field pointing back at the page and region it came from.
How it works
- You send a file (a URL or a file id you already have) and an output shape — either an inline
schemaor a savedaction. - CloudRaker fetches the bytes, parses the document, and runs extraction against your schema.
- The call holds until the run finishes — up to
?wait=seconds (60 by default, 120 max). If it finishes in time you get200with the full result. If it doesn’t, you get202with a run id to poll instead of an error. - The run and its files expire on their own (
ttl, 24 hours by default), so nothing accumulates in your organization.
Quickstart
The sample below uses a blank IRS Form W-9 as a public, stable test document, so the call works with no local files. Replace it with your own URL when you’re ready.
Want a business document rather than a blank government form? Download the sample invoice — one fictional page with a vendor, a bill-to, four line items, and totals — then send it with a presigned upload and extract against its file id.
The TypeScript and Python samples are plain HTTP so they run with nothing installed. The same call is one line on either SDK as of 0.3.0 — client.extract({ file, schema }) in TypeScript, client.extract(file=…, schema=…) in Python — and that page shows this exact extraction end to end in both languages.
Example response
Key fields
output appears only once status is processed.
Configuration
Every field below is optional unless noted.
processing on a file ref picks how the document is read: auto (default), ocr, simple, transcribe, or transcribe_diarize for audio.
Sync vs async
The endpoint is synchronous by default and degrades instead of failing.
When the run hasn’t finished by the cap, you get 202 with a handle — never a timeout error:
Poll GET /v1/runs/:id (which also accepts ?wait=) or let a webhook tell you. Send an idempotency-key header to make retries safe: a replay returns the original run and an idempotent-replay: true response header.
Large batches and scanned documents are the common causes of a 202. If you always want the handle, pass ?wait=0 and never block a request thread.
Schema inference
Don’t have a schema yet? Omit both schema and action and CloudRaker infers one from the document, then extracts against it in the same call. Add hints (up to 2,000 characters) to steer what it looks for.
The finished run carries the schema it used at config.schema, alongside the usual grounded output:
That response is trimmed — the real call on this document inferred 29 fields. The inferred schema is plain JSON Schema in the extraction dialect: every field is nullable, every field carries a description. You can send it straight back as schema with no editing.
config.schema is present whichever way the shape was decided — inferred, sent inline, or loaded from a saved action — so one code path reads the applied shape.
Inference is for exploration, not production. The model picks the fields, so two runs over the same document can return different field names and a different number of them (the two runs behind this page produced 32 and 29 fields, with form_number in one and form_type in the other). Nothing downstream of you can rely on that.
Use it once to discover the shape, then pin it: copy config.schema into your own request, or save it as an action and call that by name. Production callers should always send schema or action.
hints only applies to inference. Sending it alongside a schema or an action is a 400 invalid_request — use instructions to guide an extraction whose shape you already fixed.
Save as an action
Passing the same schema, instructions, and model on every call gets old. Saving that configuration once as an action lets you call {"file": …, "action": "invoice-lines"} and keep the request to two fields — inline fields still win when you send them.
The id and the slug are interchangeable wherever an action is referenced. Saved actions covers the catalog, the merge rules, and what the saved ramp buys you; the same actions are editable in the app under Actions.
Batch
POST /v1/extract/batch runs one saved action over many documents, minting a separate run per file — the shape you want for a nightly backfill or a queue drain.
The response is always 202 — batches never run synchronously:
There is no batch object and no batch id — runs[] is the whole handle. Each entry is either {id, statusUrl, file} for an accepted file or {file, error: {code, message}} for one rejected at admission, so a bad URL in the list never sinks the rest.
Idempotency-Key is not honoured on a batch — one key cannot address N runs, so a retried batch fans out a second time. If a batch call fails ambiguously (a 429, a timeout), list its runs by shared metadata before resending.
The body is strict: schema and hints are rejected with 400 invalid_request (“Unrecognized key”) rather than silently ignored. Save the schema as an action first — that is the point of the endpoint. A saved sign action passed as action is also a 400.
Track a batch
The batch costs one rate-limit token, and shared metadata is how you find its runs again:
That returns the three runs and their statuses in one call instead of three polls — see listing runs. For a per-run result, GET /v1/runs/:id stays authoritative, and a webhook removes the polling entirely.