Skip to main content

Batch Render โ€” Mail Merge

Tag: Batch ยท Version: v1 ยท Stability: ๐ŸŸก Beta

Generate many PDFs from a single template in one call โ€” one render per data row. The result is either a ZIP of per-row files or a single merged PDF, produced by a background job with live progress and partial-failure reporting.

Authenticate with a JWT or an X-Api-Key. Rate limits apply per workspace (same as single renders).

Async โ€” poll for status

Batch jobs run in the background. Submit the job, get back a jobId, poll the status endpoint until completed or failed, then download the result.


Submit a batch job (JSON rows)โ€‹

POST /api/templates/{id}/render-batch ยท JWT or API key ยท application/json

Request โ€” CreateBatchJsonBody
{
"rows": [
{ "name": "Alice", "total": "$1,200" },
{ "name": "Bob", "total": "$950" }
],
"output": "zip",
"fileNamePattern": "invoice-{{name}}",
"theme": { "primary": "#E11D48" }
}
FieldTypeRequiredNotes
rowsarray of objectsโœ…One render per element. Max 2,000 rows.
output"zip" | "merged"โœ…zip โ†’ per-row PDFs in a ZIP; merged โ†’ one concatenated PDF.
fileNamePatternstring | nullโœ…Token pattern for filenames inside the ZIP (e.g. invoice-{{name}}).
themeobject | nullโ€”Brand colours applied to every row of the batch: { "primary", "accent" }, each #rgb / #rrggbb or null. One theme per batch.

theme follows the same rules as on a single render โ€” see Rendering โ†’ Brand colours. It is validated when the job is submitted (an unknown key or a bad colour is a 400) and applied to each row. To render different rows in different colours, submit one batch per theme.

Returns { jobId }.

Submit a batch job (CSV / XLSX upload)โ€‹

POST /api/templates/{id}/render-batch/upload ยท JWT or API key ยท multipart/form-data

Upload a .csv or .xlsx file. Each data row becomes one render. Column headers map to template {{tokens}}. Returns { jobId }.

The upload form takes no theme: spreadsheet batches render in the template's own colours. Use the JSON endpoint above to theme a batch.


Get job statusโ€‹

GET /api/templates/{id}/render-batch/jobs/{jobId} ยท JWT or API key

Poll this endpoint until status is completed or failed.

Response (illustrative)
{
"jobId": "uuid",
"status": "processing",
"total": 50,
"completed": 23,
"failed": 0
}
statusMeaning
pendingQueued, not yet started.
processingRunning โ€” completed + failed show progress.
completedAll rows attempted; download the result.
failedJob-level failure (not a partial row failure).

List recent jobsโ€‹

GET /api/templates/{id}/render-batch/jobs ยท JWT or API key

Returns the workspace's recent batch jobs for this template.

Download resultโ€‹

GET /api/templates/{id}/render-batch/jobs/{jobId}/result ยท JWT or API key

Returns the ZIP or merged PDF. Only available when status === "completed". Results expire after 24 hours.


Partial failuresโ€‹

If individual rows fail to render, they are skipped and reported in the status response โ€” the job still completes. A job-level failure (e.g. the template is missing) marks the whole job failed.

Row capโ€‹

Maximum 2,000 rows per job. Larger datasets should be split across multiple jobs.


  • Templates โ€” the template being batch-rendered.
  • Rendering โ€” single-document render reference.
  • API Keys โ€” usage metering (batch renders are tagged api).