The request#
POST/v1/renders/batch
curl -X POST https://api.anjin.design/v1/renders/batch \
-H "Authorization: Bearer $ANJIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"format": "png",
"renders": [
{ "template": "acme_quote_1080x1080",
"modifications": [{"name": "quote", "text": "Ship it."}] },
{ "template": "acme_quote_1080x1080",
"modifications": [{"name": "quote", "text": "Then fix it."}],
"scale": 2 }
]
}'format, scale and webhook_url can be set at the batch level and overridden per row — a row-level value wins. An invalid batch-level format or scale would poison every row identically, so it fails the whole request with a 400 before anything is created.
Per-row isolation#
The response is { "results": [...] } in the same order you sent. Each entry is either a render envelope (with its own id to poll) or a structured error for that row alone:
{
"results": [
{ "id": "6f1c…", "status": "pending", "output_url": null },
{ "error": { "code": "unknown_slot", "message": "Unknown slot: quotee" } }
]
}A bad addressing key, a missing slot or insufficient credits on one row never blocks the others. Failed rows charge nothing.
Waiting vs polling#
Prefer: wait works here too: rows render concurrently and the response is a 200 with each completed row’s URLs populated. For larger batches, prefer the asynchronous flow — take the 202, then poll each row’s GET /v1/renders/:id, or attach a webhook and be told.
Limits#
- Up to 50 rows per request.
- Rows draw from the per-account rate budget by credit cost — see rate limits.
