Fill

Fill a form PDF from your source documents, with an optional human review step.
View as Markdown

POST /v1/fill takes a blank form and the documents that hold the answers, drafts every field, and returns the completed PDF. With review: "required" the run parks before producing the file so a person can correct the draft first.

How it works

  1. You send a template{"id": "…"} for a saved template, or {"url": "…"} for a one-off — and the files to draft from.
  2. CloudRaker parses the sources, reads the form’s fields (detecting them when the PDF has none), and drafts a value per field.
  3. review: "none" (the default) writes the values straight into the PDF. review: "required" parks the run at needs_input until the values are submitted.
  4. The completed file comes back as output.file, flattened (values baked in) or editable (still a fillable form).
  5. The run and its files expire on their own (ttl, 24 hours by default) unless you keep them.

Quickstart

The sample fills a blank IRS Form W-9 from one source document — both public URLs, nothing local.

$curl -X POST https://api.cloudraker.com/v1/fill \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "template": { "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf", "name": "w9.pdf" },
> "files": [{ "id": "a04d6597-4e34-4a99-94ea-964c289a4c68" }],
> "instructions": "Use the legal entity name, not the trade name.",
> "review": "none",
> "output": "flattened"
> }'

The TypeScript and Python samples are plain HTTP so they run with nothing installed. This endpoint is also a top-level method on both SDKs as of 0.3.0 — client.fill(…); that page has a full worked example.

Example response

1{
2 "object": "fill_run",
3 "id": "flr_01KYD75GGJ8QK6HN2TVZ0ABCDE",
4 "status": "processed",
5 "expiresAt": "2026-07-26T18:03:41.512Z",
6 "statusUrl": "/v1/runs/flr_01KYD75GGJ8QK6HN2TVZ0ABCDE",
7 "files": [
8 { "id": "a04d6597-4e34-4a99-94ea-964c289a4c68", "name": "w9.pdf", "status": "processed" }
9 ],
10 "output": {
11 "file": {
12 "id": "6913da38-6d0c-4b6f-9a1e-2b0f6f2b8a41",
13 "name": "w9-template (filled).pdf",
14 "url": "https://cdn.cloudraker.com/…/latest?token=…"
15 },
16 "files": [
17 { "id": "6913da38-6d0c-4b6f-9a1e-2b0f6f2b8a41", "name": "w9-template (filled).pdf", "url": "https://cdn.cloudraker.com/…/latest?token=…" }
18 ],
19 "fields": { "topmostSubform[0].Page1[0].f1_01[0]": "Acme Manufacturing Co." }
20 }
21}

Key fields

FieldWhat it is
objectAlways fill_run.
idThe run id (flr_…).
statusqueued, processing, needs_input, processed, failed, cancelled, or expired.
files[]The source documents, with per-file status.
output.fileThe completed PDF — {id, name, url}. Also at GET /v1/runs/:id/output/:name.
output.fieldsThe values written into the form, keyed by the PDF’s own field names. Empty when the sources carried nothing for any field.

The output file’s bytes are registered a moment after the run reports processed. In that window output.file can arrive without its url and the /output/ alias can answer 404 — re-fetch GET /v1/runs/:id and the URL will be there.

Configuration

FieldTypeWhat it does
template{id} or {url, name?}Required. A saved template, or an ephemeral one fetched for this run only.
files[]array of {url, name?, processing?} or {id}, 1–100Required. The documents the values are drafted from.
instructionsstring, ≤ 4000 charsGuidance for the draft (“use the 2025 fiscal year figures”).
reviewnone | requirednone (default) fills and finishes. required parks at needs_input for a human.
outputflattened | editableflattened (default) bakes the values in; editable keeps the form fillable.
actionstringA saved action — id or slug. Inline fields win over its saved config.
metadataobjectYour own key/values, echoed back on the run body (not on webhook deliveries). Max 10 KB.
webhook{url} or {id}Where to deliver terminal events. See Webhooks.
ttlinteger seconds, 1–604800How long the run and its files live. Default 24 hours, max 7 days.

An ephemeral template: {url} is fetched at run time and is not added to your template library. The fetched copy is registered as a file in your API workspace and listed by GET /v1/files while the run is alive, but it belongs to the run: it is reclaimed when the run expires, and POST /v1/runs/:id/keep moves it into the target space with everything else. Pass {id} when the same blank form is filled repeatedly — a saved template is persistent and is never touched by a run’s TTL.

Human review

With review: "required" the call returns 202 immediately and the run settles at needs_input:

1{
2 "object": "fill_run",
3 "id": "flr_01KYD7664TNP5JKHCPTKSP84MQ",
4 "status": "needs_input",
5 "expiresAt": "2026-07-26T18:04:22.338Z",
6 "statusUrl": "/v1/runs/flr_01KYD7664TNP5JKHCPTKSP84MQ",
7 "files": [
8 { "id": "a04d6597-4e34-4a99-94ea-964c289a4c68", "name": "w9.pdf", "status": "processed" }
9 ],
10 "tasks": [
11 {
12 "id": "review",
13 "title": "Review form values",
14 "url": "https://action-fill-form.actions.cloudraker.com/tasks/b1c08db9…"
15 }
16 ]
17}

tasks[] lists every human step blocking the run. Each url is a hosted review page: open it in a browser (or send it to whoever should review), correct the drafted values, and submit — the run produces the document and finishes. The link is unguessable and carries the whole capability, so treat it as a secret; it stops working once the task is submitted or the run expires.

Prefer to build your own review UI? Drive the same task over the API instead:

1

Read the task

GET /v1/runs/:id/task returns the drafted values, the fields inventory (name, type, label, page, box), and the template’s pageBoxes / pageCount — everything needed to render your own review UI. GET /v1/runs/:id/task/pdf streams the exact template bytes those boxes were measured on. Both 404 once the task is submitted or expired.

2

Submit the reviewed values

POST /v1/runs/:id/task with { "values": { "<field name>": "<value>" } }. Unknown field names are discarded, the PDF is produced, and the run finishes.

3

Read the result

GET /v1/runs/:idstatus is processed and output.file carries the completed document.

$curl -X POST https://api.cloudraker.com/v1/runs/flr_01KYD7664TNP5JKHCPTKSP84MQ/task \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{ "values": { "topmostSubform[0].Page1[0].f1_01[0]": "Acme Manufacturing Co." } }'

The hosted page and the task routes are two views of the same task — either one submits it, and whichever comes second 404s. Runs started inside the product park identically but are reviewed in the app, so they carry no tasks[].

Sync vs async

Synchronous by default with ?wait= between 0 and 120 seconds, exactly like extract. review: "required" is the exception: a run that parks for a human returns 202 immediately rather than holding the request.

Save as an action

Save the instructions, review policy, output mode, and even the template once, then call {"files": …, "action": "vendor-onboarding"}:

$curl -X POST https://api.cloudraker.com/v1/actions \
> -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "capability": "fill",
> "name": "Vendor onboarding",
> "config": { "review": "required", "outputMode": "flattened" }
> }'

Use GET /v1/actions/catalog for the exact config schema of the fill-form slug — see Saved actions.

Next steps