> ## Documentation Index
> Fetch the complete documentation index at: https://tfstudio.truefan.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Generate videos

> Render one video, or many, from a template in a single call

Starts rendering one video per row in `rows`, all from the same template. Returns immediately with a `bulk_job_id` — track progress via [Get bulk job status](/docs/api-reference/status/get-bulk-job-status) or a [webhook](/docs/guides/webhooks).

<Tip>
  This is the only generation endpoint — for a single video, call it with one row in `rows`.
</Tip>

<ParamField path="template_id" type="string" required />

<ParamField header="Authorization" type="string" required>
  `Bearer {api_key}`
</ParamField>

## Body

<ParamField body="rows" type="object[]" required>
  A non-empty list of `{variable_name: value}` objects, one per video, up to 20,000 per request. Keys should match [Get template schema](/docs/api-reference/templates/get-template-schema)'s variable names — a row missing a key just leaves that variable blank in that row's video.

  `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](/docs/api-reference/status/export-bulk-job-csv) and usable with [Get single video status](/docs/api-reference/status/get-generation-status-by-external-id) to check a row before the batch finishes. Not treated as a template variable.
</ParamField>

<ParamField body="batch_name" type="string">
  Optional label for the batch, shown back in status responses.
</ParamField>

<Info>
  `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.
</Info>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://dev-backend-ai.truefans.in/api/external/v1/templates/{template_id}/bulk-generate/" \
    -H "Authorization: Bearer $TRUEFAN_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "rows": [
        {"customer_name": "Anmol", "score": "95", "external_id": "usr_9182"},
        {"customer_name": "Rahul", "score": "88", "external_id": "usr_4471"}
      ],
      "batch_name": "August campaign"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 202 Accepted theme={null}
  {
    "bulk_job_id": "8c1f2e3a-...",
    "status": "pending",
    "row_count": 2,
    "estimated_credits": "1.36"
  }
  ```

  ```json 400 Bad Request theme={null}
  { "error": "rows is required and must be a non-empty list of objects" }
  ```

  ```json 400 Bad Request — too many rows theme={null}
  { "error": "rows exceeds the maximum of 20000 per batch", "max_rows": 20000 }
  ```

  ```json 401 Unauthorized theme={null}
  { "error": "API key required" }
  ```

  ```json 402 Payment Required theme={null}
  { "error": "insufficient_credits", "required": "1.36", "available": "0.50" }
  ```

  ```json 404 Not Found theme={null}
  { "error": "Template not found" }
  ```

  ```json 422 Unprocessable Entity theme={null}
  { "error": "This template has no configured cost — contact support" }
  ```

  ```json 500 Internal Server Error theme={null}
  { "error": "Failed to start batch" }
  ```

  ```json 503 Service Unavailable theme={null}
  { "error": "Billing service unavailable" }
  ```
</ResponseExample>

## 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`  | Template not found in this workspace                                | Confirm the `template_id` and that the key belongs to the right workspace         |
| `422`  | Template has no scenes, or no configured cost                       | 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

<ResponseField name="bulk_job_id" type="string">
  Use with [Get bulk job status](/docs/api-reference/status/get-bulk-job-status) to track the whole batch.
</ResponseField>

<ResponseField name="row_count" type="integer">
  Number of videos this batch will render — equal to `rows.length`.
</ResponseField>

<ResponseField name="estimated_credits" type="string">
  `template.estimated_credits × row_count`, deducted upfront.
</ResponseField>
