# Fill from your data

When you already have the values, from your database, a form your user filled,
wherever, fill the PDF directly. No inference: you map each value onto a field
by its `id`, and Emboss writes exactly that. (If instead you want Emboss to read
the values out of documents, see [Fill from context docs](/docs/fill-from-context).)

## Know the price first

Every route has a fixed price, and the first few calls each month are free.
To see what a specific document will cost, and whether your free tier still
covers it, send the same PDF (and any context) to `POST /forms/quote`. It is
free and it stores nothing. It does count as one call toward your hourly
[rate limit](/docs/authentication#rate-limit).

The price is exact for PDF documents. For an image, a Word file, a spreadsheet
or text it is an estimate from the file's size: the job bills the size Emboss
measures when it reads the document, which can be higher, for example for a
photo of a dense page.

```bash
curl -X POST https://api.getemboss.ai/forms/quote \
  -H "Authorization: Bearer sk_..." \
  -F "file=@application.pdf" \
  -F "context=@customer.json"
```

The answer prices each route you could call next and says, per kind of work,
whether the free tier covers it. The sample shows the shape; the amounts
follow the live price list:

```json
{
  "pages": 3,
  "context_pages": 1,
  "already_fillable": false,
  "effective": "2026-09-07",
  "billing": { "has_card": false, "exempt": false, "billing_url": "https://getemboss.ai/dashboard/billing" },
  "lines": {
    "create_form": { "cents": 5, "free": true,
      "kinds": { "create": { "covered": true, "reason": "within_allowance", "remaining": 4 } } },
    "create_and_fill_from_context": { "cents": 8, "free": false,
      "kinds": { "create": { "covered": true, "reason": "within_allowance", "remaining": 4 },
                 "with_context": { "covered": false, "reason": "allowance_used", "remaining": 0 } } },
    "fill_from_data": { "cents": 2, "free": true,
      "kinds": { "standard_fill": { "covered": true, "reason": "within_allowance", "remaining": 4 } } },
    "verify": { "cents": 1, "free": true,
      "kinds": { "verify": { "covered": true, "reason": "within_allowance", "remaining": 4 } } }
  }
}
```

`reason` is one of `"within_allowance"` (free, with how many free calls remain
after this one), `"allowance_used"` (this month's free calls are spent),
`"over_page_cap"` (the document is longer than the free tier allows), or
`"exempt"`. A line is `free` only when every kind it charges is covered. When
`has_card` is true a line that is not free is charged to the card on file;
otherwise the real call answers `402` with the same reason.

The free-tier verdict is judged on the form's page count for `create`,
`standard_fill`, and `verify`, but on the form's pages plus the context's
page-equivalents for `with_context`, since that is the combined size the
`with-context` route itself bills against. The fourth line, `verify`, prices
checking a filled PDF with `POST /forms/{form_id}/verify`.

The call itself can fail before it ever gets to price anything: `400` means
the upload wasn't a PDF, `413` means it was too many pages, too much context,
too many context files, or too large, and `422` means the `file` field was
missing from the request.

## 1. Create the form and wait for detection

Upload the flat PDF, then poll until it's `ready` (see
[Tracking jobs](/docs/tracking-jobs)):

```bash
curl -X POST https://api.getemboss.ai/forms \
  -H "Authorization: Bearer sk_..." \
  -F "file=@./w9.pdf"
```

## 2. Read the contract to find field ids

```bash
curl https://api.getemboss.ai/forms/6c47f7f5-f921-4698-910f-95dd7d81310b/contract \
  -H "Authorization: Bearer sk_..."
```

Each field has an integer `id`: that's what you'll target. See
[The contract shape](/docs/the-contract-shape).

## 3. Open a session

```bash
curl -X POST https://api.getemboss.ai/sessions \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "form_id": "6c47f7f5-f921-4698-910f-95dd7d81310b" }'
```

`201 Created`:

```json
{
  "session_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "next_prompt": null,
  "missing": [1, 3],
  "pending_confirmation": [],
  "form_state": {
    "fields": {
      "1": { "candidates": [], "confidence": null, "evidence": [], "history": [], "invalid_reason": null,
             "note": null, "origin": null, "reoffered": false, "source": null, "status": "unfilled", "value": null }
    },
    "turn_count": 0
  }
}
```

`missing` lists the required fields still empty; `form_state.fields` has one
entry per field id (one is shown). The session's own `status` (`active`, then
`completed` once filled) is on `GET /sessions/{sid}`.

## 4. Write your values

`PUT /sessions/{sid}/fields` with a list of `field_id` → `value` updates:

```bash
curl -X PUT https://api.getemboss.ai/sessions/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/fields \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "updates": [
        { "field_id": 1, "value": "Analytical Engines LLC" },
        { "field_id": 3, "value": "12-3456789" }
      ] }'
```

```json
{ "session_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "applied": [1, 3] }
```

An unknown `field_id` or a value the field won't accept returns `422` with the
refused ids in `invalid_field_ids`, and nothing in that request is applied.

Send every value as a string, a checkbox's too (`"yes"`, not `true`).

| Field `type` | Accepted values |
| --- | --- |
| `text`, `date`, `comb`, `signature` | Any text. |
| `checkbox` | A yes or no word. `yes`, `y`, `true`, `on`, `checked`, `x` or `1` ticks the box; `no`, `n`, `false`, `off`, `unchecked`, `0` or an empty value leaves it empty. |
| `radio` | Exactly one of the field's `options[].value` from [the contract](/docs/the-contract-shape) (sometimes a generated `opt_0`, `opt_1`). |

Saying yes to more than one box of one Yes/No question returns `422` with those
ids in `conflicting_field_ids`.

## 5. Fill and download

```bash
curl -X POST https://api.getemboss.ai/sessions/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/fill \
  -H "Authorization: Bearer sk_..."

curl https://api.getemboss.ai/sessions/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/pdf \
  -H "Authorization: Bearer sk_..." \
  -o filled.pdf
```

That's the whole deterministic path: no guessing, just the values you provided.

## Retention

`POST /forms` takes an optional `retention` body field: `ephemeral` or
`account_default`. Leave it out and the account's own default applies. See
[Ephemeral processing](/docs/ephemeral-processing) for the window and what a
410 means once a form is swept.

## See also

- [Fill PDFs from your own data](https://getemboss.ai/use-cases/fill-pdfs-from-your-data)
- [Filling a PDF from data](https://getemboss.ai/glossary/fill-pdf-from-data)
- [Fill from context docs](https://getemboss.ai/docs/fill-from-context)
- [Ephemeral processing](https://getemboss.ai/docs/ephemeral-processing)
- [Standard fill](https://getemboss.ai/docs/reference/sessions)
- [Get the contract](https://getemboss.ai/docs/reference/get-contract)
