Batches
Give this prompt to your AI agent. The agent does the task for you.
Read https://thirds.ai/docs/api-reference/batches and help me choose the right thirds.ai endpoint and write a request. Check the fields and credentials in this reference.
Render one saved template version once per data row, poll each row, retry failed rows, and download a ZIP of the files that succeeded.
See all API resources or read API keys and requests.
Endpoints
createBatch
POST /v1/batches
Create a render batch
Render one saved template version once per data row as PDF, PNG, JPEG, or WebP. The account plan sets how many rows one run accepts: 10 on Free and a pack-only account, 50 on Starter, 100 on Growth, and 200 on Scale. A run over that limit answers 400 batch_row_limit with error.plan_limit. Validates every row against the version's schema before any job exists. Creates one normal render job per row as account and key concurrency allow. Remaining rows stay pending until a later retry or the background drain. The ledger reserves one credit per admitted job, settles it on success, and releases it on failure or cancellation. quoted_credits is the row count, not a discount.
Authentication: bearer API key. See authentication.
| Parameter | Location | Required | Rule |
|---|---|---|---|
Idempotency-Key | header | Yes | {"type":"string","minLength":1,"maxLength":255,"pattern":"^[ -~]+$"} |
Request body: application/json, BatchCreate.
| Status | Meaning | Body |
|---|---|---|
| 201 | The batch was created, or an earlier request with the same idempotency key and body is replayed. | application/json: Batch |
| 400 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 401 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 403 | The authenticated account is suspended. The code is account_suspended. | application/json: ErrorEnvelope |
| 404 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 405 | The method is not allowed on this route. | application/json: ErrorEnvelope |
| 409 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 413 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 415 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 429 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 431 | The request has more than 64 headers or more than 32 KiB of header names and values. | application/json: ErrorEnvelope |
| 500 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 503 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
getBatch
GET /v1/batches/{id}
Get a render batch's status
Returns the batch with each row's own state and, once any row has succeeded, a signed archive_url for the ZIP of every succeeded file. GET never starts billed work.
Authentication: bearer API key. See authentication.
| Parameter | Location | Required | Rule |
|---|---|---|---|
id | path | Yes | {"type":"string","pattern":"^batch_[0-9a-f]{32}$"} |
| Status | Meaning | Body |
|---|---|---|
| 200 | The batch's current status. | application/json: Batch |
| 401 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 403 | The authenticated account is suspended. The code is account_suspended. | application/json: ErrorEnvelope |
| 404 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 405 | The method is not allowed on this route. | application/json: ErrorEnvelope |
| 431 | The request has more than 64 headers or more than 32 KiB of header names and values. | application/json: ErrorEnvelope |
| 500 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
retryBatch
POST /v1/batches/{id}/retry
Retry a batch's failed, cancelled, or pending rows
Creates one new job for every row whose last attempt failed or was cancelled, and admits still-pending rows as concurrency allows. A queued, running, or already succeeded row is left untouched. Retry never bills a row that already succeeded.
Authentication: bearer API key. See authentication.
| Parameter | Location | Required | Rule |
|---|---|---|---|
id | path | Yes | {"type":"string","pattern":"^batch_[0-9a-f]{32}$"} |
| Status | Meaning | Body |
|---|---|---|
| 200 | The batch after retry, with a new job for each row that was retried. | application/json: BatchRetry |
| 401 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 403 | The authenticated account is suspended. The code is account_suspended. | application/json: ErrorEnvelope |
| 404 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 405 | The method is not allowed on this route. | application/json: ErrorEnvelope |
| 429 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 431 | The request has more than 64 headers or more than 32 KiB of header names and values. | application/json: ErrorEnvelope |
| 500 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
cancelBatch
POST /v1/batches/{id}/cancel
Cancel a batch's pending and queued rows
Stops rows that have no job yet and cancels queued jobs. Running jobs finish. Succeeded files stay downloadable. Cancelled and failed rows cost nothing.
Authentication: bearer API key. See authentication.
| Parameter | Location | Required | Rule |
|---|---|---|---|
id | path | Yes | {"type":"string","pattern":"^batch_[0-9a-f]{32}$"} |
| Status | Meaning | Body |
|---|---|---|
| 200 | The batch after cancel. | application/json: Batch |
| 401 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 403 | The authenticated account is suspended. The code is account_suspended. | application/json: ErrorEnvelope |
| 404 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
| 405 | The method is not allowed on this route. | application/json: ErrorEnvelope |
| 431 | The request has more than 64 headers or more than 32 KiB of header names and values. | application/json: ErrorEnvelope |
| 500 | The one error envelope every backend response uses. | application/json: ErrorEnvelope |
getBatchArchive
GET /v1/batches/archive/{token}
Download a batch's ZIP archive
Stream a ZIP of one batch's succeeded rows, in requested order with numbered filenames such as 001.pdf, plus manifest.json recording that order and any failed or cancelled rows. The link carries its own authority, so no other credential is read. The manifest never includes customer data.
Authentication: no credential required.
| Parameter | Location | Required | Rule |
|---|---|---|---|
token | path | Yes | The signed archive link. {"type":"string"} |
| Status | Meaning | Body |
|---|---|---|
| 200 | The ZIP archive of succeeded rows plus manifest.json. | application/zip: {"type":"string","format":"binary"} |
| 403 | The link is genuine but its time is over. | application/json: ErrorEnvelope |
| 404 | The link is not valid, or the batch has no succeeded row to archive. | application/json: ErrorEnvelope |
| 405 | The method is not allowed on this route. | application/json: ErrorEnvelope |
| 431 | The request has more than 64 headers or more than 32 KiB of header names and values. | application/json: ErrorEnvelope |
| 500 | An internal error occurred. | application/json: ErrorEnvelope |
Schemas
BatchCreate
| Field | Required | Description and type |
|---|---|---|
template_id | Yes | TemplateId |
version | No | Omitted to use the template's latest version at creation time. The batch pins that exact version. {"type":"integer","minimum":1} |
format | Yes | {"type":"string","enum":["pdf","png","jpeg","webp"]} |
rows | Yes | 1 to 200 JSON objects. Each object is one render. 200 is the system cap; the account plan can allow fewer. The CSV parser lives in the studio; this API accepts rows only. {"type":"array","items":{"type":"object"},"minItems":1,"maxItems":200} |
Schema rules: {"type":"object","additionalProperties":false}.
BatchRow
| Field | Required | Description and type |
|---|---|---|
position | Yes | {"type":"integer","minimum":0} |
state | Yes | {"type":"string","enum":["queued","running","succeeded","failed","cancelled"]} |
error | Yes | {"type":["object","null"],"properties":{"code":{"type":"string"}},"required":["code"],"additionalProperties":false} |
download_url | Yes | {"type":["string","null"]} |
Schema rules: {"type":"object","additionalProperties":false}.
Batch
| Field | Required | Description and type |
|---|---|---|
id | Yes | {"type":"string","pattern":"^batch_[0-9a-f]{32}$"} |
template_id | Yes | TemplateId |
version | Yes | {"type":"integer","minimum":1} |
format | Yes | {"type":"string","enum":["pdf","png","jpeg","webp"]} |
created_at | Yes | {"type":"string","format":"date-time"} |
state | Yes | {"type":"string","enum":["queued","running","complete","partial","failed","cancelled"]} |
quoted_credits | Yes | The row count. Each successful file settles one credit. Failed and cancelled rows cost nothing. There is no bulk discount. {"type":"integer","minimum":1,"maximum":200} |
rows | Yes | {"type":"array","items":{"$ref":"#/components/schemas/BatchRow"}} — BatchRow |
archive_url | Yes | A signed ZIP download link, present once any row has succeeded. {"type":["string","null"]} |
Schema rules: {"type":"object","additionalProperties":false}.
BatchRetry
Schema rules: Batch.
Shared errors, headers, and authentication schemes are in shared types and security.