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 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 (the default is 60 requests per
window).
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, you're over the window's limit. Wait briefly and
retry that request — an exponential backoff (1s, 2s, 4s…) works well. Lowering
concurrency is the simplest way to avoid hitting it in the first place.
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 and Tracking jobs.