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

# Bulk Video Translation

> Submit large batches of videos to the HeyGen Bulk Video Translation API. Translate hundreds of videos in parallel into multiple target languages from a single.

## Prerequisites

* Python 3.6+
* The `requests` library:
  ```bash theme={null}
  pip install requests
  ```
* A HeyGen API key from the [Subscriptions & API](https://app.heygen.com/settings?from=\&nav=Subscriptions%20%26%20API) section of your dashboard — see the [API Key guide](/docs/api-key).

This page walks through a batch script. For one-off translations see [Speed mode](/docs/video-translate) or [Precision mode](/docs/video-translation-precision). Each row in the CSV becomes one call to [`POST /v3/video-translations`](/reference/create-video-translation).

## Prepare Your CSV

Create a file named `bulk_translation_input.csv` with these columns:

| Column            | Required | Description                                                                                                                                   |
| ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `title`           | Yes      | Title for the translation job.                                                                                                                |
| `output_language` | Yes      | Target language code (use [`GET /v3/video-translations/languages`](/reference/list-supported-translation-languages) to discover valid codes). |
| `url`             | Yes      | Public video download URL.                                                                                                                    |
| `folder_id`       | No       | Folder ID to organize translations.                                                                                                           |

Example:

```csv theme={null}
title,output_language,url,folder_id
"Product Demo","Spanish","https://example.com/demo.mp4","folder_123"
"Onboarding","French","https://example.com/onboard.mp4",""
"Q4 Earnings","Japanese","https://example.com/q4.mp4",""
```

<Info>
  The `url` field must be a publicly accessible video download URL. If you paste the URL into an incognito browser window, the video should play without any login or password.
</Info>

You can also start from this [Google Sheet template](https://docs.google.com/spreadsheets/d/1ykARUasMW0tHFbrFYnGCIINhga-wJLiu39zCDXnhZIQ/edit?usp=sharing) and export it as CSV.

## The Script

Save the following as `bulk_translate.py`:

```python theme={null}
import os
import csv
import requests

API_URL = "https://api.heygen.com/v3/video-translations"
API_KEY = os.environ.get("HEYGEN_API_KEY", "YOUR_API_KEY_HERE")

HEADERS = {
    "accept": "application/json",
    "content-type": "application/json",
    "x-api-key": API_KEY,
}

def main():
    input_csv = "bulk_translation_input.csv"
    output_csv = "bulk_translation_results.csv"
    results = []

    with open(input_csv, mode="r", newline="", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        fieldnames = list(reader.fieldnames) + ["video_translation_id"]

        for row in reader:
            payload = {
                "video": {
                    "type": "url",
                    "url": row["url"],
                },
                "output_languages": [row["output_language"]],
                "title": row["title"],
            }

            folder_id = row.get("folder_id", "").strip()
            if folder_id:
                payload["folder_id"] = folder_id

            try:
                resp = requests.post(API_URL, headers=HEADERS, json=payload)
                resp.raise_for_status()
                data = resp.json()
                ids = data.get("data", {}).get("video_translation_ids", [])
                translation_id = ids[0] if ids else ""
                print(f"Success: '{row['title']}' -> {translation_id}")
            except requests.exceptions.RequestException as e:
                translation_id = ""
                print(f"Error: '{row['title']}' -> {e}")

            row["video_translation_id"] = translation_id
            results.append(row)

    with open(output_csv, mode="w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(results)

    print(f"\nResults saved to {output_csv}")

if __name__ == "__main__":
    main()
```

## Running the Script

1. **Set your API key** as an environment variable (recommended):
   ```bash theme={null}
   export HEYGEN_API_KEY="your-api-key-here"
   ```
   Alternatively, replace `YOUR_API_KEY_HERE` in the script directly.
2. **Place your CSV** (`bulk_translation_input.csv`) in the same directory as the script.
3. **Run the script:**
   ```bash theme={null}
   python bulk_translate.py
   ```
   On macOS or Linux, use `python3` if needed:
   ```bash theme={null}
   python3 bulk_translate.py
   ```
4. **Review results.** The script creates `bulk_translation_results.csv` with all original columns plus a `video_translation_id` column.

## Checking Translation Status

Use the `video_translation_id` values from the results CSV to poll each translation's status via [`GET /v3/video-translations/{video_translation_id}`](/reference/get-video-translation). For a hands-off pattern, pass `callback_url` in the payload instead — see [Webhooks](/docs/webhooks).

```bash theme={null}
curl --request GET \
  --url 'https://api.heygen.com/v3/video-translations/<video_translation_id>' \
  --header 'accept: application/json' \
  --header 'x-api-key: <your-api-key>'
```

When the status is `completed`, the response includes a presigned `video_url` to download the translated video.

<Tip>
  For better security, always store your API key in an environment variable rather than hardcoding it in the script.
</Tip>
