Browse the docs Open Close
Snap batches
Up to 100 snaps from one call.
A batch renders up to 100 snaps from ONE template, with a different set of variants per item. The call is always asynchronous: it returns 202 with a batch id, and the items render in the background. Poll the batch to read progress and to collect the image URLs, and cancel it to stop the items that have not started. One webhook is posted when the batch finishes. Creating a batch requires an active subscription or trial. Reading and canceling one do not.
/v1/snaps/batches
Create a batch of snaps
Renders up to 100 snaps from one template. Every item carries its own `variants` and an optional `identifier` you use to recognize it in the result.
The response is always 202. Nothing is charged at accept time. Each item costs 1 credit when it renders.
`type`, `format` and `transparent` apply to every item in the batch. An item that needs a different format belongs in a different batch.
The API always renders the template's **published** version.
Credits — 0 credits at accept time (HTTP 202). Each item is charged 1 credit when it reaches completed. An item that fails costs nothing. A repeated `idempotency_key` returns the first batch and starts no second one.
Request body
Content-Type: application/json
| Field | Type | Required | Validation | Description |
|---|---|---|---|---|
template_id |
string | Yes | required, exists templates.uuid scoped to company |
UUID of the template every item renders from. |
items |
array | Yes | required, array, min:1, max:100 |
One entry per snap. Over 100 entries returns 422 and creates nothing. |
items[].variants |
array | No | each image_url must be a public http or https address |
Per-layer content overrides for this item. |
items[].identifier |
string | No | sometimes, nullable, string, max:191 |
Your own name for this item. Defaults to item_1, item_2, and so on. |
title |
string | No | sometimes, string, max:255 |
A name for the batch, shown in the account. Defaults to "API batch". |
webhook_url |
string | No | nullable, url, max:2048, must be a public http or https address |
ONE request is posted to this address when the batch finishes. A host that resolves to a private, loopback, link-local or reserved range is rejected with 422. |
type |
string | No | sometimes, in:image,pdf |
Output type for every item. Defaults to image. |
format |
string | No | sometimes, in:png,jpeg,webp |
Image output format for every item. Defaults to png. |
transparent |
boolean | No | sometimes, boolean; 422 when combined with format=jpeg |
Render every item on a transparent background. Valid for png and webp only. |
idempotency_key |
string | No | sometimes, nullable, string, max:191, letters/digits/underscore/hyphen only |
Send the same key when you retry after a timeout. The retry returns the same batch and starts no second one. Keys are honored for 24 hours and are scoped to your account. A key already used by POST /v1/snaps returns 409. |
The whole batch is checked against the credit balance before any item is created. A batch of 100 against 40 credits creates nothing, not 40 items.
The balance check is not a reservation. Two batches accepted a second apart read the same balance, so a caller can queue more items than the balance covers. Each item is still charged only when it renders.
Over 100 items returns 422 on `errors.items` and creates nothing. The request is never truncated in silence.
Exactly one webhook is posted, when the batch finishes. There is no per-item webhook on this endpoint.
`webhook_url` must be a public address. A host that resolves to a private, loopback, link-local or reserved range is rejected with 422.
A response to a repeated `idempotency_key` carries an `X-Idempotent-Replay: true` header.
Every response carries an `X-Request-Uuid` header. Quote it in support tickets.
A batch holds one of five statuses. `pending` and `processing` mean it is still running. The three terminal statuses are `completed`, `failed` and `canceled`, and a batch never leaves one. `completed` means the batch ran to the end and at least one item rendered, so read the `failed` count as well as the status. `failed` means zero items rendered. At every terminal status `completed + failed + canceled` equals `total_rows`.
Example request
curl
curl -X POST https://snapsbrew.com/api/v1/snaps/batches \
-H 'Authorization: Bearer <your-token>' \
-H 'Content-Type: application/json' \
-d '{"template_id":"<uuid>","title":"October launch","items":[{"identifier":"row-1","variants":[{"layer":"headline","text":"Hello"}]},{"identifier":"row-2","variants":[{"layer":"headline","text":"World"}]}]}'
Example responses
{
"uuid": "7c1f2a9e-0b44-4a1e-9f2b-5d3c8e1a7b60",
"title": "October launch",
"status": "processing",
"total_rows": 3,
"processed_rows": 0,
"completed": 0,
"pending": 3,
"failed": 0,
"canceled": 0,
"credits_charged": 0,
"status_url": "https://snapsbrew.com/api/v1/snaps/batches/7c1f2a9e-0b44-4a1e-9f2b-5d3c8e1a7b60"
}
{
"message": "This idempotency_key already belongs to a single snap. Use a new key for a batch."
}
{
"message": "You have reached your snap quota."
}
{
"message": "A batch accepts at most 100 items. Split the request into smaller batches."
}
/v1/snaps/batches/{batchUuid}
Read a batch
Returns the counts, the running credit total, and every item with its status and image URL. Poll this about every 5 seconds and stop when `status` is `completed`, `failed` or `canceled`.
This endpoint does not require an active subscription, so a customer whose plan lapsed can still collect work they already paid for.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
batchUuid |
path | string | Yes | The batch id returned by POST /v1/snaps/batches. |
A batch holds one of five statuses. `pending` and `processing` mean it is still running. The three terminal statuses are `completed`, `failed` and `canceled`, and a batch never leaves one. `completed` means the batch ran to the end and at least one item rendered, so read the `failed` count as well as the status. `failed` means zero items rendered. At every terminal status `completed + failed + canceled` equals `total_rows`.
`credits_charged` is read from the billing ledger, not counted from `completed`. It rises between polls.
`media_url` is set only on an item with status `completed`.
`last_error` on a failed item carries the render error as the renderer reported it. Treat it as a message for a person, never as a stable code to branch on.
A batch id that belongs to another account returns 404, the same as an id that does not exist.
Example request
curl
curl 'https://snapsbrew.com/api/v1/snaps/batches/<batch-uuid>' \
-H 'Authorization: Bearer <your-token>'
Example responses
{
"uuid": "7c1f2a9e-0b44-4a1e-9f2b-5d3c8e1a7b60",
"title": "October launch",
"status": "completed",
"total_rows": 2,
"processed_rows": 2,
"completed": 1,
"pending": 0,
"failed": 1,
"canceled": 0,
"credits_charged": 1,
"status_url": "https://snapsbrew.com/api/v1/snaps/batches/7c1f2a9e-0b44-4a1e-9f2b-5d3c8e1a7b60",
"items": [
{
"id": "9f1c2d3e",
"identifier": "row-1",
"status": "completed",
"media_url": "https://snapsbrew.com/storage/snaps/9f1c2d3e.png",
"last_error": null
},
{
"id": "4b8a7c6d",
"identifier": "row-2",
"status": "failed",
"media_url": null,
"last_error": "Render failed."
}
]
}
{
"message": "No batch with that id exists in your account."
}
/v1/snaps/batches/{batchUuid}/cancel
Cancel a batch
Stops a batch that is still running.
An item that already rendered keeps its image and stays billed. An item that had not started is marked `canceled` and costs nothing. An item that is rendering at that moment can still finish and can still be charged.
This cannot be undone. A canceled batch cannot be resumed. Start a new batch for the items you still want.
Like the read endpoint, this does not require an active subscription: stopping work only lowers the bill.
Credits — Nothing is charged by this call. Items that already rendered keep the credit they cost. Items that never started cost nothing.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
batchUuid |
path | string | Yes | The batch id returned by POST /v1/snaps/batches. |
Canceling twice is safe. A batch that already holds a terminal status is returned unchanged.
One webhook is posted, carrying `event: snap-import.canceled`.
An item that is rendering when the cancel lands can still complete and can still be charged. The counts in the response are the truth at that moment.
A batch id that belongs to another account returns 404, the same as an id that does not exist.
Example request
curl
curl -X POST 'https://snapsbrew.com/api/v1/snaps/batches/<batch-uuid>/cancel' \
-H 'Authorization: Bearer <your-token>'
Example responses
{
"uuid": "7c1f2a9e-0b44-4a1e-9f2b-5d3c8e1a7b60",
"title": "October launch",
"status": "canceled",
"total_rows": 3,
"processed_rows": 3,
"completed": 1,
"pending": 0,
"failed": 0,
"canceled": 2,
"credits_charged": 1,
"status_url": "https://snapsbrew.com/api/v1/snaps/batches/7c1f2a9e-0b44-4a1e-9f2b-5d3c8e1a7b60",
"items": [
{
"id": "9f1c2d3e",
"identifier": "row-1",
"status": "completed",
"media_url": "https://snapsbrew.com/storage/snaps/9f1c2d3e.png",
"last_error": null
},
{
"id": "4b8a7c6d",
"identifier": "row-2",
"status": "canceled",
"media_url": null,
"last_error": null
},
{
"id": "2e5f9a1b",
"identifier": "row-3",
"status": "canceled",
"media_url": null,
"last_error": null
}
]
}
{
"message": "No batch with that id exists in your account."
}