# Batch fill

Fill one form from every row of a spreadsheet. Upload a CSV or XLSX, map its
columns to the form's fields once, and Emboss fills a separate PDF for each row.
Each row is a deterministic fill with no inference, so it is fast and cheap. For
the single-form version of this, see [Fill from your data](/docs/fill-from-data).

There are two steps. First get a column mapping that you review and edit, then run
the batch. The mapping is computed once because your spreadsheet columns are the
same for every row.

## 1. Create the form and wait for detection

Upload the flat PDF and poll until it is `ready` (see
[Tracking jobs](/docs/tracking-jobs)):

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

## 2. Suggest a column mapping

Send your spreadsheet to `suggest-mapping`. Emboss reads the column headers and
the form's fields and proposes a mapping. This is one context fill.

```bash
curl -X POST https://api.getemboss.ai/forms/{form_id}/suggest-mapping \
  -H "Authorization: Bearer sk_..." \
  -F "file=@./customers.csv"
```

```json
{
  "mapping": {
    "Company": { "field_id": 0, "confidence": "high" },
    "Phone": { "field_id": 1, "confidence": "high" }
  },
  "unmapped_columns": ["Internal Notes"]
}
```

Each `field_id` is the integer id from the form's contract (see
[The contract shape](/docs/the-contract-shape)). Review the mapping. Change any
`field_id`, drop a column, or add one Emboss missed. If you already know the
mapping you want, you can skip this step and supply your own in the next one.

## 3. Run the batch

Send the same spreadsheet plus the resolved mapping as a JSON string. Emboss
returns a `batch_id` right away and fills the rows in the background.

```bash
curl -X POST https://api.getemboss.ai/forms/{form_id}/fill-batch \
  -H "Authorization: Bearer sk_..." \
  -F "file=@./customers.csv" \
  -F 'mapping={"Company":{"field_id":0},"Phone":{"field_id":1}}'
```

```json
{ "batch_id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d" }
```

The response status is 202 Accepted. The batch runs in the background. Poll it with the call below.

Each row is one standard fill. A row that cannot be filled is recorded as failed
and does not stop the rest of the batch.

## 4. Poll the batch

```bash
curl https://api.getemboss.ai/forms/fill-batch/{batch_id} \
  -H "Authorization: Bearer sk_..."
```

```json
{
  "status": "complete",
  "total": 500,
  "filled": 498,
  "failed": 2,
  "results": [
    { "row": 1, "status": "filled", "pdf_url": "/forms/fill-batch/{batch_id}/rows/1/pdf" },
    { "row": 7, "status": "failed", "error": "row 7: one or more values are not valid for their field; checkboxes take yes or no (field ids: 12)" }
  ]
}
```

The `results` array has one entry per row. Filled rows carry a `pdf_url`. Failed
rows carry an `error`, so you can fix that row and run it again.

Row numbers count the spreadsheet's data rows from 1, after
rows that are entirely blank are dropped, so they can differ from your
sheet's own line numbers.

## 5. Download the filled PDFs

Fetch one row's PDF:

```bash
curl https://api.getemboss.ai/forms/fill-batch/{batch_id}/rows/1/pdf \
  -H "Authorization: Bearer sk_..." -o row-1.pdf
```

Or get all of them in one zip:

```bash
curl https://api.getemboss.ai/forms/fill-batch/{batch_id}/zip \
  -H "Authorization: Bearer sk_..." -o batch.zip
```

## Limits and pricing

A batch is capped at 1000 rows. The mapping call is one context fill and each
filled row is one standard fill, both drawing from your monthly free allowance;
a row that fails is not charged. Without a payment method on file, a batch with
more rows than the free fills you have left this month is refused with `402`
before anything is filled: the answer's `code` is `over_free_tier`, and it
carries `rows`, `remaining` and `billing_url`. See [Pricing](/pricing) for the
rates.

## Validation errors

`fill-batch` checks everything before it starts the job, so a bad request creates
no batch and bills nothing.

- `400` if the spreadsheet is empty or unreadable, the mapping is not valid JSON,
  the mapping names a column not in the spreadsheet or a field not in the form, or
  there are more than 1000 rows.
- `409` if the form is not `ready`.
- `404` if the form or the batch is not yours.
- `413` if the spreadsheet is over 10 MB.

`fill-batch` takes no `Idempotency-Key`: a retried request starts, and bills,
a second batch. Check `GET /forms/fill-batch/{batch_id}` before you send it again.

## See also

- [Batch fill PDFs from a spreadsheet](https://getemboss.ai/use-cases/batch-fill-from-spreadsheet)
- [Checkbox and radio fields](https://getemboss.ai/glossary/pdf-checkbox-field)
- [Bulk runs](https://getemboss.ai/docs/bulk-runs)
- [Batch fill](https://getemboss.ai/docs/reference/batch)
- [Fill PDF forms in Make scenarios](https://getemboss.ai/integrations/make)
- [Fill PDF forms in Pipedream workflows](https://getemboss.ai/integrations/pipedream)
