> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.cloudraker.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.cloudraker.com/_mcp/server.

# Fill

`POST /v1/fill` fills a form PDF and returns the completed file. Send exactly one of two inputs:

* **`values`** — the field values to write, keyed by field name. Deterministic: no drafting pass, no model call.
* **`files`** — source documents. CloudRaker drafts one value per field.

Fill works best as a two-step flow. **Configure once:** upload the blank form as a [template](/paperwork/capabilities/templates), inspect its fields, curate them, and save the result on a fill config. **Fill many times:** call `POST /v1/fill` with `action` and either `values` or `files`. See [Configure a form once](#configure-a-form-once).

## How it works

1. You pick the **form**. Send `template` inline — `{"id": "…"}` for a [saved template](/paperwork/capabilities/templates), or `{"url": "…"}` for a one-off. Or send `action` naming a [saved config](/paperwork/capabilities/actions) that carries one. Inline wins when both are present.
2. You pick the **input**. `values` writes your JSON straight into the form. `files` parses the sources and drafts a value per field. A fill run never re-detects fields: it uses the fields saved on the config, or the form's own field inventory when none are saved.
3. In `files` mode, CloudRaker writes the drafted values into the PDF.
4. The completed file comes back as `output.file`. It is `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](/paperwork/developers/runs#keep-a-run) them.

## Quickstart

The sample drafts a blank IRS Form W-9 from one source document. Both are public URLs. Nothing is local.

```bash title="curl"
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.",
    "output": "flattened"
  }'
```

```ts title="TypeScript"
const res = await fetch("https://api.cloudraker.com/v1/fill", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CLOUDRAKER_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    template: { url: "https://www.irs.gov/pub/irs-pdf/fw9.pdf", name: "w9.pdf" },
    files: [{ id: "a04d6597-4e34-4a99-94ea-964c289a4c68" }],
  }),
});

const run = await res.json();
console.log(run.status, run.output?.file?.name);
```

```python title="Python"
import os, requests

res = requests.post(
    "https://api.cloudraker.com/v1/fill",
    headers={"Authorization": f"Bearer {os.environ['CLOUDRAKER_API_KEY']}"},
    json={
        "template": {"url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf", "name": "w9.pdf"},
        "files": [{"id": "a04d6597-4e34-4a99-94ea-964c289a4c68"}],
    },
)

run = res.json()
print(run["status"], run.get("output", {}).get("file", {}).get("name"))
```

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](/paperwork/developers/sdks) as of 0.3.0: `client.fill(…)`. That page has a full worked example.

## Example response

```json
{
  "object": "fill_run",
  "id": "flr_01KYD75GGJ8QK6HN2TVZ0ABCDE",
  "status": "processed",
  "expiresAt": "2026-07-26T18:03:41.512Z",
  "statusUrl": "/v1/runs/flr_01KYD75GGJ8QK6HN2TVZ0ABCDE",
  "files": [
    { "id": "a04d6597-4e34-4a99-94ea-964c289a4c68", "name": "w9.pdf", "status": "processed" }
  ],
  "output": {
    "file": {
      "id": "6913da38-6d0c-4b6f-9a1e-2b0f6f2b8a41",
      "name": "w9-template (filled).pdf",
      "url": "https://cdn.cloudraker.com/…/latest?token=…"
    },
    "files": [
      { "id": "6913da38-6d0c-4b6f-9a1e-2b0f6f2b8a41", "name": "w9-template (filled).pdf", "url": "https://cdn.cloudraker.com/…/latest?token=…" }
    ],
    "fields": { "topmostSubform[0].Page1[0].f1_01[0]": "Acme Manufacturing Co." }
  }
}
```

## Key fields

| Field           | What it is                                                                                                                  |
| --------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `object`        | Always `fill_run`.                                                                                                          |
| `id`            | The run id (`flr_…`).                                                                                                       |
| `status`        | `queued`, `processing`, `needs_input`, `processed`, `failed`, `cancelled`, or `expired`.                                    |
| `files[]`       | The source documents, with per-file `status`. In `values` mode, this holds a run-scoped copy of the template instead.       |
| `output.file`   | The completed PDF: `{id, name, url}`. Also at `GET /v1/runs/:id/output/:name`.                                              |
| `output.fields` | The 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.

## Configure a form once

Curating a form once makes every later fill predictable. The saved fields fix the schema: field names, human labels, per-field guidance, and which fields to skip.

#### Save the blank form as a template

`POST /v1/templates` with a `url`, or the presigned-upload shape. See [Templates](/paperwork/capabilities/templates#add-a-template).

#### Inspect it

`POST /v1/templates/:id/inspect` returns `{ fields, schema, pageBoxes, pageCount, detected, templateHash }`. Each field carries `name`, `type`, `label`, `page`, and `box`. CloudRaker detects fields when the PDF has none of its own — `detected` says so. Templates over 32 MB answer `413 template_too_large`.

#### Curate the fields

Rewrite each field's `label`, add a `description` with filling guidance, and set `ignore: true` on fields no run should touch. Keep `name`, `type`, `page`, and `box` as returned.

#### Save fields and hash on a fill config

`POST /v1/fill/configs` with the curated `fields` and the `templateHash` from the same inspect. The hash lets you spot a stale curation after the template changes.

```bash
curl -X POST https://api.cloudraker.com/v1/fill/configs \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Vendor onboarding",
    "config": {
      "template": "23e0a865-0be9-45b1-a491-f1b6bd58a31a",
      "instructions": "Use the legal entity name, not the trade name.",
      "output": "flattened",
      "fields": [
        {
          "name": "topmostSubform[0].Page1[0].f1_01[0]",
          "type": "text",
          "label": "Legal entity name",
          "description": "The registered legal name, never the trade name.",
          "page": 0,
          "box": { "x": 58.6, "y": 118.0, "width": 517.4, "height": 14 },
          "ignore": false
        }
      ],
      "templateHash": "9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab"
    }
  }'
```

A fill config accepts exactly these keys: `template` (a template or file id), `instructions`, `output`, `fields`, and `templateHash`. An unknown key answers `400` instead of being stored dead. `PATCH /v1/fill/configs/{idOrSlug}` deep-merges the keys you send and keeps all other saved keys.

From then on, every call is one line of config:

```bash
# deterministic — your values, no model call
curl -X POST https://api.cloudraker.com/v1/fill \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "action": "vendor-onboarding", "values": { "topmostSubform[0].Page1[0].f1_01[0]": "Acme Manufacturing Co." } }'

# drafted — values are drafted from the source documents
curl -X POST https://api.cloudraker.com/v1/fill \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "action": "vendor-onboarding", "files": [{ "id": "a04d6597-4e34-4a99-94ea-964c289a4c68" }] }'
```

`template` is optional when `action` carries one — the saved template applies, and sending `template` inline still wins. Any other inline field also wins over its saved counterpart.

A fill run never re-inspects the form. Inspect runs at configure time only. A run uses the config's saved `fields`; with none saved, it uses the form's own field inventory and labels.

`GET`, `PATCH` and `DELETE /v1/fill/configs/{idOrSlug}` manage a config. `GET /v1/fill/configs` lists them. `/v1/actions` still works as a deprecated alias. See [Saved configs](/paperwork/capabilities/actions).

## Fill from values

`values` mode is deterministic. Your JSON is coerced to each field's type and written into the PDF. No model is called.

Key `values` by field name — the names come from [inspect](/paperwork/capabilities/templates#inspect-the-fields), or from the `fields` saved on the config. Its `schema` describes the exact object `values` accepts.

A key that matches no field fails the run fast, before anything is written or metered. The run reports `status: "failed"` with `error.code: "unknown_fields"`, and `error.message` lists the offending keys.

## Configuration

| Field          | Type                                                  | What it does                                                                                                                                           |
| -------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `template`     | `{id}` or `{url, name?}`                              | A saved [template](/paperwork/capabilities/templates), or an ephemeral one fetched for this run only. Optional when `action` carries one; inline wins. |
| `values`       | object                                                | The field values to write, keyed by field name. Send this or `files`, never both.                                                                      |
| `files[]`      | array of `{url, name?, processing?}` or `{id}`, 1–100 | The documents the values are drafted from. Send this or `values`, never both.                                                                          |
| `instructions` | string, ≤ 4000 chars                                  | Guidance for the draft ("use the 2025 fiscal year figures"). `files` mode only.                                                                        |
| `output`       | `flattened` \| `editable`                             | `flattened` (default) bakes the values in. `editable` keeps the form fillable.                                                                         |
| `action`       | string                                                | A [saved config](/paperwork/capabilities/actions), by id or slug. Inline fields win over its saved config.                                             |
| `metadata`     | object                                                | Your 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](/paperwork/developers/webhooks).                                                                      |
| `ttl`          | integer seconds, 1–604800                             | How long the run and its files live. Default 24 hours, max 7 days.                                                                                     |

An ephemeral `template: {url}` is fetched at run time. It is not added to your template library. The fetched copy is registered as a file in your API workspace. `GET /v1/files` lists it while the run is alive. But the copy belongs to the run: it is reclaimed when the run expires. `POST /v1/runs/:id/keep` moves it into the target space with everything else.

Pass `{id}` when you fill the same blank form repeatedly. A saved template is persistent. A run's TTL never touches it.

## Sync vs async

Synchronous by default, with `?wait=` between `0` and `120` seconds, exactly like [extract](/paperwork/capabilities/extract#sync-vs-async).

## Next steps

#### [Templates](/capabilities/templates)

Store a blank form once, inspect its fields, and fill it by id.

#### [Sign](/capabilities/sign)

Send the completed document out for signature.

#### [Runs](/developers/runs)

Statuses, downloading outputs, TTL, and keeping a result.

#### [Webhooks](/developers/webhooks)

Get a notification when a run parks or finishes instead of polling.