Bulk Rendering
Bulk rendering submits one template + many variable sets in a single request — Zvid fans it out into individual render jobs, each with its own credits, status, and output. It's the scale half of templates: personalized videos from a CRM export, one video per product, per city, per employee.
Submitting a batch
curl -X POST https://api.zvid.io/api/render/bulk/api-key \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "tpl_xxxxxxxxxxxxxxxxxxxx",
"name": "spring-campaign",
"items": [
{ "variables": { "firstName": "Amira", "city": "Cairo" }, "name": "spring-amira" },
{ "variables": { "firstName": "Omar", "city": "Alexandria" } },
{ "variables": { "firstName": "Lina", "city": "Giza" } }
],
"webhookUrl": "https://example.com/hooks/bulk-done"
}'
Envelope fields:
| Field | Required | Notes |
|---|---|---|
template or payload | one of them | A stored tpl_… id, or a full inline project (with variables defaults). |
items | yes | 1–500 entries; each is { variables, name? }. Your plan's maxBulkItems may be lower — validation errors report it. |
variables | no | Batch-level values merged under every item's variables. |
overrides | no | Output knobs applied to every job (name, dimensions, format, …). |
name | no | Batch name shown in the dashboard. |
webhookUrl | no | Per-request webhook — called per job completion. |
Best-effort validation
Items are validated individually. Valid items become jobs immediately;
invalid ones are returned in errors — each entry carries the item's original
request index as item (0-based) plus field-level details — and the batch is
only rejected outright when the envelope is malformed or every item fails:
{
"bulkId": "blk_…",
"queued": true,
"totalJobs": 2,
"rejectedItems": 1,
"errors": [
{
"item": 1,
"error": "Validation failed",
"details": [
{
"field": "payload.duration",
"message": "Duration must be at least 0.1 seconds"
}
]
}
],
"failedToQueue": 0,
"creditsReserved": 12,
"clientRoom": "api:42:7",
"queueAhead": 0,
"jobs": [
{
"jobId": "550e8400-…",
"index": 0,
"name": "spring-amira",
"creditsReserved": 6
},
{ "jobId": "6ba7b810-…", "index": 2, "name": null, "creditsReserved": 6 }
]
}
jobs[].index is each queued job's original position in items, so you can
line results back up with your source rows even when some items were rejected.
Fix the failed rows and resubmit just those — the dashboard's bulk page has a fix-and-resubmit flow and CSV export for exactly this.
Credits
Each job reserves its own credits when it starts and refunds on failure — there is no batch-level charge. See Credits, Plans & Limits.
Tracking a batch
| Endpoint | Auth | Purpose |
|---|---|---|
GET /api/render/bulk | JWT | List your bulk batches |
GET /api/render/bulk/{id} | JWT or API key | Batch status with per-item job states and results |
Individual jobs are also visible through the normal
GET /api/jobs/{id} endpoint, and each fires
webhook events on completion.
Bulk images
POST /api/render/image/bulk (and /image/bulk/api-key) is the same contract
with type: "image" enforced — useful for thumbnail sets and social-card
batches. Image credit pricing (1 credit per 10 images) makes large image
batches cheap: 25 images ≈ 3 credits.