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.

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):

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.

curl -X POST https://api.getemboss.ai/forms/{form_id}/suggest-mapping \
  -H "Authorization: Bearer sk_..." \
  -F "file=@./customers.csv"
{
  "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). 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.

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}}'
{ "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

curl https://api.getemboss.ai/forms/fill-batch/{batch_id} \
  -H "Authorization: Bearer sk_..."
{
  "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:

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:

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 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.