> ## Documentation Index
> Fetch the complete documentation index at: https://heygen-1fa696a7.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Videos

> Submit up to 100 video creation requests in a single call. Queue avatar, image, and cinematic avatar videos together, then poll one batch id for per-item progress.

## Overview

Video batches let you submit many videos in one request instead of calling [`POST /v3/videos`](/reference/create-video) once per video. You send an array of video payloads, get back a single `batch_id` right away, and poll that one id for the status and `video_id` of every item.

Each item in a batch is a standard video creation payload — the exact shape [`POST /v3/videos`](/reference/create-video) accepts — so any [Digital Twin](/generate-avatar-video), [image](/image-to-video), or [Cinematic Avatar](/cinematic-avatar) video you can create on its own can be batched.

<Note>
  A batch holds up to **100** items. Submission is asynchronous: the response acknowledges the batch, and each video renders on its own. Poll the batch to collect video ids as they become available.
</Note>

## Create a Batch

* Endpoint: `POST /v3/videos/batches`
* Purpose: Queue up to 100 video creation payloads and return a `batch_id` immediately.

### Quick Example

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/videos/batches" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "October product update — regional cuts",
    "callback_url": "https://example.com/hooks/heygen",
    "videos": [
      {
        "type": "avatar",
        "avatar_id": "YOUR_DIGITAL_TWIN_LOOK_ID",
        "script": "Hello from the North America team!",
        "voice_id": "YOUR_VOICE_ID"
      },
      {
        "type": "avatar",
        "avatar_id": "YOUR_DIGITAL_TWIN_LOOK_ID",
        "script": "Hello from the EMEA team!",
        "voice_id": "YOUR_VOICE_ID"
      }
    ]
  }'
```

```json Response theme={null}
{
  "data": {
    "batch_id": "batch_abc123"
  }
}
```

The call returns `202 Accepted` — the batch is queued, not finished. Use the returned `batch_id` to [poll for progress](#get-a-batch).

### Request Body

| Parameter      | Type   | Required | Default | Description                                                                                                                |
| -------------- | ------ | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------- |
| `videos`       | array  | Yes      | —       | Video creation requests, each identical in shape to [`POST /v3/videos`](/reference/create-video). Between 1 and 100 items. |
| `title`        | string | No       | `null`  | Display name for the batch, shown in the HeyGen app.                                                                       |
| `callback_url` | string | No       | `null`  | [Webhook](/docs/webhooks) URL invoked once when every item in the batch reaches a terminal state.                          |

Each entry in `videos` is discriminated by `type`:

| `type`             | Item shape                           | Guide                                  |
| ------------------ | ------------------------------------ | -------------------------------------- |
| `avatar`           | Avatar video from a script and voice | [Digital Twin](/generate-avatar-video) |
| `image`            | Video from a still image             | [Image to Video](/image-to-video)      |
| `cinematic_avatar` | Cinematic Avatar video               | [Cinematic Avatar](/cinematic-avatar)  |

### Idempotency

Pass an `Idempotency-Key` header to make retries safe — replaying the same key returns the original batch instead of creating a duplicate. If a request with that key is still being processed, the API responds with `409`.

## Get a Batch

* Endpoint: `GET /v3/videos/batches/{batch_id}`
* Purpose: Return the batch's aggregate status plus one page of items with their `video_id` and per-item status.

### Quick Example

```bash theme={null}
curl -X GET "https://api.heygen.com/v3/videos/batches/batch_abc123?limit=100" \
  -H "x-api-key: YOUR_API_KEY"
```

```json Response theme={null}
{
  "data": {
    "batch_id": "batch_abc123",
    "title": "October product update — regional cuts",
    "status": "processing",
    "total_items": 2,
    "counts_by_status": {
      "completed": 1,
      "processing": 1
    },
    "created_at": 1711929600,
    "items": [
      {
        "item_index": 0,
        "status": "completed",
        "video_id": "vid_9f2c...",
        "error": null
      },
      {
        "item_index": 1,
        "status": "processing",
        "video_id": null,
        "error": null
      }
    ],
    "has_more": false,
    "next_token": null
  }
}
```

### Query Parameters

| Parameter | Type    | Required | Default | Description                                                       |
| --------- | ------- | -------- | ------- | ----------------------------------------------------------------- |
| `limit`   | integer | No       | `100`   | Items per page, `1`–`100`.                                        |
| `token`   | string  | No       | —       | Opaque pagination cursor from a previous response's `next_token`. |

### Response Fields

| Field              | Type    | Description                                                                        |
| ------------------ | ------- | ---------------------------------------------------------------------------------- |
| `batch_id`         | string  | Batch identifier.                                                                  |
| `title`            | string  | Batch display name, if one was set.                                                |
| `status`           | string  | Aggregate status derived from item states: `processing`, `completed`, or `failed`. |
| `total_items`      | integer | Number of items submitted in this batch.                                           |
| `counts_by_status` | object  | Item counts keyed by item status.                                                  |
| `created_at`       | integer | Batch creation time as a Unix timestamp.                                           |
| `items`            | array   | One page of batch items, ordered by `item_index`.                                  |
| `has_more`         | boolean | Whether more items exist beyond this page.                                         |
| `next_token`       | string  | Cursor for the next page; `null` on the last page.                                 |

Each entry in `items`:

| Field        | Type    | Description                                                                                                                                                         |
| ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `item_index` | integer | Zero-based position of this item in the submitted `videos` array.                                                                                                   |
| `status`     | string  | Item status: `queued`, `processing`, `completed`, or `failed`.                                                                                                      |
| `video_id`   | string  | Video id, present once the underlying video has been created. Use it with [`GET /v3/videos/{video_id}`](/reference/get-video) for the full record and download URL. |
| `error`      | object  | Failure details, present when `status` is `failed`.                                                                                                                 |

## Tracking completion

You have two ways to know when work finishes, and they pair well:

* **Webhook (push).** Set `callback_url` on the batch to be notified once, when the last item reaches a terminal state. See [Webhooks](/docs/webhooks) to register an endpoint and verify signatures.
* **Polling (pull).** Call `GET /v3/videos/batches/{batch_id}` and read `counts_by_status`. Individual items surface a `video_id` the moment their video is created, so you can start downloading finished videos while the rest of the batch is still rendering.

For large batches, page through `items` with `limit` and `next_token` until `has_more` is `false`, then fetch each finished video with [`GET /v3/videos/{video_id}`](/reference/get-video).
