curl -X POST "https://dev-backend-ai.truefans.in/api/external/v1/image-templates/{template_id}/bulk-generate/" \
-H "Authorization: Bearer $TRUEFAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{"customer_name": "Anmol", "city": "Mumbai", "external_id": "usr_9182"},
{"customer_name": "Rahul", "city": "Pune", "external_id": "usr_4471"}
],
"batch_name": "Diwali greetings"
}'
{
"bulk_job_id": "8c1f2e3a-...",
"status": "pending",
"row_count": 2,
"estimated_credits": "0.00724"
}
{ "error": "rows is required and must be a non-empty list of objects" }
{ "error": "rows exceeds the maximum of 20000 per batch", "max_rows": 20000 }
{ "error": "API key required" }
{ "error": "insufficient_credits", "required": "0.00724", "available": "0.00100" }
{ "error": "Image template not found" }
{ "error": "Image template has no layers or base image configured" }
{ "error": "Failed to start batch" }
{ "error": "Billing service unavailable" }
Image Generation
Generate images
Render one image, or many, from an image template in a single call
POST
/
api
/
external
/
v1
/
image-templates
/
{template_id}
/
bulk-generate
/
curl -X POST "https://dev-backend-ai.truefans.in/api/external/v1/image-templates/{template_id}/bulk-generate/" \
-H "Authorization: Bearer $TRUEFAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{"customer_name": "Anmol", "city": "Mumbai", "external_id": "usr_9182"},
{"customer_name": "Rahul", "city": "Pune", "external_id": "usr_4471"}
],
"batch_name": "Diwali greetings"
}'
{
"bulk_job_id": "8c1f2e3a-...",
"status": "pending",
"row_count": 2,
"estimated_credits": "0.00724"
}
{ "error": "rows is required and must be a non-empty list of objects" }
{ "error": "rows exceeds the maximum of 20000 per batch", "max_rows": 20000 }
{ "error": "API key required" }
{ "error": "insufficient_credits", "required": "0.00724", "available": "0.00100" }
{ "error": "Image template not found" }
{ "error": "Image template has no layers or base image configured" }
{ "error": "Failed to start batch" }
{ "error": "Billing service unavailable" }
Starts rendering one image per row in
In the CSV export, an image batch’s final column is
rows, all from the same image template. Returns immediately with a bulk_job_id — track progress via Get image batch status or a webhook.
Discovery is shared with video — list image templates and read their schema through List templates and Get template schema with
?type=IMAGE_TEMPLATE. Only generation and results have their own paths: /image-templates/{template_id}/bulk-generate/ and /image-bulk-jobs/. The request body is identical to Generate videos — for a single image, call it with one row in rows.string
required
string
required
Bearer {api_key}Body
object[]
required
A non-empty list of
{variable_name: value} objects, one per image, up to 20,000 per request. Keys should match Get template schema’s variable names — a row missing a key just leaves that placeholder blank in that row’s image.external_id is a reserved key you can include in any row — your own identifier for that row, echoed back unchanged in the CSV export and usable with Get single image status to check a row before the batch finishes. Not treated as a template variable.string
Optional label for the batch, shown back in status responses.
rows — not a CSV file or URL — is the only way to submit a batch through this API. Serialize your data directly into the request body.curl -X POST "https://dev-backend-ai.truefans.in/api/external/v1/image-templates/{template_id}/bulk-generate/" \
-H "Authorization: Bearer $TRUEFAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{"customer_name": "Anmol", "city": "Mumbai", "external_id": "usr_9182"},
{"customer_name": "Rahul", "city": "Pune", "external_id": "usr_4471"}
],
"batch_name": "Diwali greetings"
}'
{
"bulk_job_id": "8c1f2e3a-...",
"status": "pending",
"row_count": 2,
"estimated_credits": "0.00724"
}
{ "error": "rows is required and must be a non-empty list of objects" }
{ "error": "rows exceeds the maximum of 20000 per batch", "max_rows": 20000 }
{ "error": "API key required" }
{ "error": "insufficient_credits", "required": "0.00724", "available": "0.00100" }
{ "error": "Image template not found" }
{ "error": "Image template has no layers or base image configured" }
{ "error": "Failed to start batch" }
{ "error": "Billing service unavailable" }
Errors
| Status | Meaning | What to do |
|---|---|---|
400 | rows missing, empty, not a list of objects, or over 20,000 rows | Fix the request body, or split into multiple batches |
401 | Missing or invalid API key | Check the Authorization header |
402 | Insufficient credits | Top up the workspace’s account |
404 | Image template not found in this workspace | Confirm the template_id and that the key belongs to the right workspace |
422 | Image template has no base image or layers configured | Fix the template in the editor |
500 | Failed to prepare or dispatch the batch after credits were reserved | Credits are reversed on a best-effort basis — verify your balance before retrying |
503 | Billing service temporarily unavailable | Safe to retry |
Response fields
string
Use with Get image batch status to track the whole batch.
integer
Number of images this batch will render — equal to
rows.length.string
0.00181 × variable_count × row_count, deducted upfront. See How images are priced below.How images are priced
Images are priced per variable, not per render — a flat0.00181 credits for every variable the template declares, charged on every row.
per_row = 0.00181 × variable_count
estimated_credits = per_row × row_count
variable_count is the number of variables the template declares — the same set of columns Get template schema returns — not the number of keys a given row happens to fill. Every row in a batch is therefore priced identically, and the count is frozen from the template as it existed when you submitted, so editing the template mid-batch cannot change what you are charged.
This is a different model from video, which charges the template’s own
estimated_credits per row. An image batch is typically orders of magnitude cheaper — a 4-variable template over 500 rows costs 0.00181 × 4 × 500 = 3.62 credits.Getting the results
The status endpoints are shared with video and need no change — a batch of images reports through exactly the same Get image batch status, Get single image status and CSV export you already use. One difference in the payload: each row carriesoutput_type: "image", and the finished asset lands in result_image_url. Image rows do not carry result_video_url at all — the field is absent, not null.
Row from an image batch
{
"generation_id": "f339beb9-305d-4a01-89ef-669b7ec70de3",
"row_index": 0,
"external_id": "usr_9182",
"output_type": "image",
"status": "completed",
"result_image_url": "https://assets-studio.truefans.in/editor/.../a.png"
}
If you already parse batch results for video, branch on
output_type and read result_image_url on image rows. Code that reaches for result_video_url unconditionally will find the key missing rather than empty.result_image_url in place of result_video_url — the rest of the header (external_id, generation_id, then the batch’s variable names) is unchanged.