# Bulk runs

The simplest way to fill many PDFs is the batch endpoint. Upload a spreadsheet,
map the columns once, and Emboss fills a PDF per row for you. See
[Batch fill](/docs/batch-fill) for that flow.

You can also fill many PDFs with a client-side loop, calling the single-form
endpoints yourself. Reach for the loop when you want full control over
concurrency and retries, or when your inputs are separate PDFs rather than rows of
one form.

## The pattern

Each form follows the usual chain: create, poll until `ready`, fill, download.
For a batch, run several of those chains concurrently, but cap how many are in
flight so you don't blow past the rate limit: 60 calls per API key per clock
hour that start work (creating, filling, preparing, verifying, reading back,
quoting, suggesting a mapping, starting a batch, or searching the library).
Status checks, downloads and commits don't count. A form you create and then
fill from your own data takes two of those calls.

```js
async function runBatch(pdfPaths, key, concurrency = 5) {
  const queue = [...pdfPaths];
  const results = [];
  async function worker() {
    while (queue.length) {
      const path = queue.shift();
      try {
        results.push({ path, status: await fillOne(path, key) });
      } catch (err) {
        results.push({ path, error: String(err) });
      }
    }
  }
  await Promise.all(Array.from({ length: concurrency }, worker));
  return results;
}
```

`fillOne` is your single-form chain (create → poll → fill → download). Keep
`concurrency` modest: 5 to 10 in flight is plenty and leaves rate-limit
headroom.

## Handling rate limits

If a request returns `429`, this API key has used its calls for the current
clock hour. The count starts again at the top of the next hour (UTC), and the
answer carries no `Retry-After` header, so a short backoff keeps failing. Wait
for the next hour, spread a large run across hours, or ask for a higher limit
at contact@getemboss.ai.

## Track what succeeded

There's no automatic idempotency across a batch, so record which inputs
finished. If a run is interrupted, re-submit only the ones that didn't complete.
Resubmitting a form just creates a new one.

For the single-form flow each worker runs, see
[Fill from your data](/docs/fill-from-data) and [Tracking jobs](/docs/tracking-jobs).

## See also

- [Bulk-fill PDFs programmatically](https://getemboss.ai/use-cases/bulk-fill-pdfs)
- [Form flattening](https://getemboss.ai/glossary/pdf-form-flattening)
- [The contract shape](https://getemboss.ai/docs/the-contract-shape)
- [Batch fill](https://getemboss.ai/docs/reference/batch)
