Prerequisites
- Python 3.6+
- The
requests library:
- A HeyGen API key from the Subscriptions & API section of your dashboard.
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 to discover valid codes). |
url | Yes | Public video download URL. |
folder_id | No | Folder ID to organize translations. |
Example:
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",""
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.
You can also start from this Google Sheet template and export it as CSV.
The Script
Save the following as bulk_translate.py:
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
- Set your API key as an environment variable (recommended):
export HEYGEN_API_KEY="your-api-key-here"
Alternatively, replace YOUR_API_KEY_HERE in the script directly.
- Place your CSV (
bulk_translation_input.csv) in the same directory as the script.
- Run the script:
On macOS or Linux, use
python3 if needed:
python3 bulk_translate.py
- 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:
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.
For better security, always store your API key in an environment variable rather than hardcoding it in the script.