POST /api/translate
Translates a video clip’s audio to a different language using ElevenLabs’ AI dubbing technology. The system:
- Extracts the original audio track
- Uploads to ElevenLabs Dubbing API
- Waits for AI-generated dubbed audio (preserves speaker voice characteristics)
- Replaces the original audio with the dubbed version
This endpoint is synchronous and may take 2-5 minutes depending on video length and ElevenLabs queue.
Authentication
Your ElevenLabs API key for dubbing services
Request Body
The job ID from /api/process
Zero-based index of the clip to translate
Target language code (e.g., es for Spanish, fr for French). See language list
Source language code (auto-detected if omitted)
Specific video filename to translate (for effect chaining)
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"clip_index": 0,
"target_language": "es",
"source_language": "en" // Optional
}
Response
Always true on successful translation
Relative URL to the translated video file
{
"success": true,
"new_video_url": "/videos/550e8400-e29b-41d4-a716-446655440000/translated_es_video_123_clip_1.mp4"
}
GET /api/translate/languages
Returns the list of supported languages for translation.
Response
Array of language objects with code, name, and native name
{
"languages": [
{"code": "en", "name": "English", "native_name": "English"},
{"code": "es", "name": "Spanish", "native_name": "Español"},
{"code": "fr", "name": "French", "native_name": "Français"},
{"code": "de", "name": "German", "native_name": "Deutsch"},
{"code": "it", "name": "Italian", "native_name": "Italiano"},
{"code": "pt", "name": "Portuguese", "native_name": "Português"},
{"code": "pl", "name": "Polish", "native_name": "Polski"},
{"code": "tr", "name": "Turkish", "native_name": "Türkçe"},
{"code": "ru", "name": "Russian", "native_name": "Русский"},
{"code": "nl", "name": "Dutch", "native_name": "Nederlands"},
{"code": "cs", "name": "Czech", "native_name": "Čeština"},
{"code": "ar", "name": "Arabic", "native_name": "العربية"},
{"code": "zh-cn", "name": "Chinese (Simplified)", "native_name": "简体中文"},
{"code": "ja", "name": "Japanese", "native_name": "日本語"},
{"code": "ko", "name": "Korean", "native_name": "한국어"},
{"code": "hi", "name": "Hindi", "native_name": "हिन्दी"}
]
}
Supported Languages
ElevenLabs supports 30+ languages including:
| Code | Language | Native |
|---|
en | English | English |
es | Spanish | Español |
fr | French | Français |
de | German | Deutsch |
it | Italian | Italiano |
pt | Portuguese | Português |
pl | Polish | Polski |
tr | Turkish | Türkçe |
ru | Russian | Русский |
nl | Dutch | Nederlands |
cs | Czech | Čeština |
ar | Arabic | العربية |
zh-cn | Chinese (Simplified) | 简体中文 |
ja | Japanese | 日本語 |
ko | Korean | 한국어 |
hi | Hindi | हिन्दी |
id | Indonesian | Bahasa Indonesia |
ms | Malay | Bahasa Melayu |
ta | Tamil | தமிழ் |
fi | Finnish | Suomi |
sv | Swedish | Svenska |
uk | Ukrainian | Українська |
Call /api/translate/languages for the most up-to-date list with all supported languages.
Error Codes
| Code | Description |
|---|
| 400 | Missing X-ElevenLabs-Key header |
| 404 | Job ID not found |
| 404 | Metadata file not found |
| 404 | Clip index out of range |
| 404 | Video file not found at specified path |
| 500 | ElevenLabs API error (quota exceeded, invalid language, etc.) |
Examples
Translate to Spanish
curl -X POST http://localhost:8000/api/translate \
-H "X-ElevenLabs-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"clip_index": 0,
"target_language": "es"
}'
Response:
{
"success": true,
"new_video_url": "/videos/550e8400-e29b-41d4-a716-446655440000/translated_es_video_123_clip_1.mp4"
}
Get Supported Languages
curl http://localhost:8000/api/translate/languages
Python SDK Example
import requests
# Translate to Spanish
url = "http://localhost:8000/api/translate"
headers = {"X-ElevenLabs-Key": "YOUR_KEY"}
payload = {
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"clip_index": 0,
"target_language": "es",
"source_language": "en" # Optional
}
response = requests.post(url, headers=headers, json=payload)
result = response.json()
if result["success"]:
print(f"Translated video: {result['new_video_url']}")
# Get language list
lang_response = requests.get("http://localhost:8000/api/translate/languages")
languages = lang_response.json()["languages"]
print(f"Supported languages: {len(languages)}")
JavaScript/Fetch Example
// Translate video
const translateVideo = async (jobId, clipIndex, targetLanguage) => {
const response = await fetch('http://localhost:8000/api/translate', {
method: 'POST',
headers: {
'X-ElevenLabs-Key': 'YOUR_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
job_id: jobId,
clip_index: clipIndex,
target_language: targetLanguage
})
});
return await response.json();
};
// Get languages
const getLanguages = async () => {
const response = await fetch('http://localhost:8000/api/translate/languages');
const data = await response.json();
return data.languages;
};
// Usage
const languages = await getLanguages();
console.log('Available languages:', languages);
const result = await translateVideo(
'550e8400-e29b-41d4-a716-446655440000',
0,
'es'
);
console.log('Translated video:', result.new_video_url);
Translate and Add Subtitles
import requests
job_id = "550e8400-e29b-41d4-a716-446655440000"
headers_elevenlabs = {"X-ElevenLabs-Key": "YOUR_KEY"}
# 1. Translate to Spanish
translate_resp = requests.post(
"http://localhost:8000/api/translate",
headers=headers_elevenlabs,
json={
"job_id": job_id,
"clip_index": 0,
"target_language": "es"
}
)
translated_file = translate_resp.json()["new_video_url"].split("/")[-1]
print(f"Translated to Spanish: {translated_file}")
# 2. Add Spanish subtitles (auto-detects dubbed video and re-transcribes)
subtitle_resp = requests.post(
"http://localhost:8000/api/subtitle",
json={
"job_id": job_id,
"clip_index": 0,
"input_filename": translated_file,
"position": "bottom",
"font_size": 16
}
)
final_file = subtitle_resp.json()["new_video_url"]
print(f"Spanish video with Spanish subtitles: {final_file}")
How It Works
- Audio Extraction: FFmpeg extracts audio from the video
- Upload: Audio file sent to ElevenLabs Dubbing API
- AI Processing: ElevenLabs analyzes speech, generates dubbed audio in target language
- Polling: API polls ElevenLabs every 10 seconds for completion
- Download: Dubbed audio track downloaded
- Merge: FFmpeg replaces original audio with dubbed audio
- Output: New video file saved with
translated_{language}_ prefix
Voice Preservation
ElevenLabs’ AI dubbing preserves:
- Speaker characteristics: Tone, pitch, and vocal style
- Emotion: Excitement, sarcasm, emphasis
- Timing: Lip-sync alignment where possible
- Background audio: Music and sound effects preserved
- Processing Time: 2-5 minutes for typical 30-60 second clips
- ElevenLabs Queue: May vary based on API load
- Blocking: This endpoint is synchronous (waits for dubbing to complete)
- Costs: ElevenLabs charges per character/second of dubbed audio
Translated videos replace the original in the job result’s video_url field and metadata.json. The original video is preserved on disk.
Next Steps