Skip to content
DashboardGet API Key

Translating Videos

Translate a video into up to 10 languages with natural voices, lip sync, background audio, custom subtitles, and completion webhooks.

Video Translate turns one source video into translated versions in up to 10 target languages. CHAMELAION transcribes the speech, translates it, voices each speaker, keeps the background audio, and lip-syncs the result (background audio and lip sync are on by default). Each target language returns a video, an audio track, and an SRT subtitle file.

Send the video as a public URL or as a direct upload. Both endpoints validate the request, create an asynchronous job, and return a request_id. Poll it for the result, or set webhook_url to be notified.

Use POST /v1/video-translate/generate when the source video is available at a public URL.

Terminal window
curl --request POST \
https://api.chamelaion.com/api/v1/video-translate/generate \
--header "Authorization: Bearer $CHAMELAION_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"reference_id": "translation-001",
"source_language": "en",
"target_languages": ["de", "fr"],
"webhook_url": "https://example.com/webhooks/chamelaion",
"inputs": [
{
"type": "video",
"url": "https://storage.googleapis.com/chamelaion-test-media/video.mp4"
}
]
}'

The URL must be reachable by CHAMELAION. Signed URLs work as long as they stay valid until the video is downloaded.

ParameterTypeRequiredDescription
inputsarrayYesExactly one item with type set to "video" and the video url
target_languagesarrayYes1–10 unique language codes, excluding the source language
source_languagestringNoLanguage spoken in the video. Detected automatically when omitted
reference_idstringNoYour own identifier (max 255 characters), usable for retrieval and filtering
webhook_urlstringNoHTTPS URL that receives a POST when the request completes or fails
disable_background_audiobooleanNoSet to true to drop the original background audio (default: false)
disable_lip_syncbooleanNoSet to true to skip lip sync and only replace the audio (default: false)
formalitybooleanNoSet to true for a formal tone in translations, false for a casual tone (default: false)
modelstringNoexpressive (default) or classic; see Choose a speech model
configobjectNoOptional subtitles, speaker voices, and advanced settings

Set the top-level model field to choose the speech model. When you omit it, CHAMELAION uses expressive.

ValueProduct nameTarget-language support
expressiveCHAMELAION ExpressiveAll 91 canonical target languages; default
classicCHAMELAION ClassicThe legacy 29 canonical target languages

The product UI may show 93 Expressive and 31 Classic languages because it also counts accepted regional aliases. Existing integrations may continue to send config.tts_model (eleven_v4 or eleven_multilingual_v2), but that field is deprecated. If both fields are sent, they must select the same model.

This example selects Classic, translates to English, and disables both background audio and lip sync:

Terminal window
curl --request POST \
https://api.chamelaion.com/api/v1/video-translate/generate \
--header "Authorization: Bearer $CHAMELAION_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"source_language": "de",
"target_languages": ["en"],
"disable_background_audio": true,
"disable_lip_sync": true,
"model": "classic",
"inputs": [{
"type": "video",
"url": "https://storage.googleapis.com/chamelaion-test-media/video.mp4"
}]
}'

This example selects Expressive and translates to Kannada with background audio and lip sync enabled:

Terminal window
curl --request POST \
https://api.chamelaion.com/api/v1/video-translate/generate \
--header "Authorization: Bearer $CHAMELAION_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"source_language": "en",
"target_languages": ["kn"],
"disable_background_audio": false,
"disable_lip_sync": false,
"model": "expressive",
"inputs": [{
"type": "video",
"url": "https://storage.googleapis.com/chamelaion-test-media/video.mp4"
}]
}'

Use POST /v1/video-translate/generate-with-media to send the video as multipart/form-data. It accepts the same settings as form fields. target_languages can be a JSON array or a comma-separated string, and config is a JSON-encoded object.

Terminal window
curl --request POST \
https://api.chamelaion.com/api/v1/video-translate/generate-with-media \
--header "Authorization: Bearer $CHAMELAION_API_KEY" \
--form "video=@/absolute/path/source-video.mp4;type=video/mp4" \
--form 'target_languages=["de","fr"]' \
--form 'model=expressive' \
--form "source_language=en" \
--form "reference_id=translation-upload-001" \
--form "webhook_url=https://example.com/webhooks/chamelaion"

The video can be up to 2 GiB and must contain a video stream.

By default, CHAMELAION transcribes and translates the speech automatically. To control the exact wording, upload the source subtitles as source_srt and translated subtitles as target_srt.<language>. Every target SRT language must also appear in target_languages. Languages without a target SRT are translated automatically.

Terminal window
curl --request POST \
https://api.chamelaion.com/api/v1/video-translate/generate-with-media \
--header "Authorization: Bearer $CHAMELAION_API_KEY" \
--form "video=@/absolute/path/source-video.mp4;type=video/mp4" \
--form 'target_languages=["de"]' \
--form "source_language=en" \
--form "source_srt=@/absolute/path/source-en.srt;type=application/x-subrip" \
--form "target_srt.de=@/absolute/path/target-de.srt;type=application/x-subrip"

Each cue’s text must start with Speaker N:, where N is a non-negative integer:

1
00:00:00,000 --> 00:00:02,500
Speaker 0: Welcome back.
2
00:00:02,600 --> 00:00:05,000
Speaker 1: Thanks for having me.
  • SRT files must be UTF-8 encoded, with file names ending in .srt.
  • Source and target files must have the same number of cues and the same speakers.
  • Cue timings must fit within the video’s duration.

Syntax errors return 400 immediately. Cue, speaker, and timing mismatches are checked once the video is processed, and fail the request with an error_message.

You can also send subtitles inline in config on either endpoint, as config.source_srt and config.target_srts.<language>. Each is an object with a content string and optional file_name and language. Don’t send the same subtitle both inline and as a file.

List the voices available to your account. Filter by language, gender, application, search, or favorite:

Terminal window
curl --request GET \
"https://api.chamelaion.com/api/v1/video-translate/voices?language=en&limit=50" \
--header "Authorization: Bearer $CHAMELAION_API_KEY"
{
"voices": [
{
"voice_id": "21m00Tcm4TlvDq8ikWAM",
"name": "Rachel",
"default_name": "Rachel",
"description": "Calm, young adult female voice.",
"language": "en",
"application": "narration",
"gender": "Female",
"is_favorite": false
}
],
"pagination": { "limit": 50, "offset": 0, "total": 1 }
}

Map speaker IDs to a voice_id in config.speaker_voices. Keys are the speaker numbers from the Speaker N: cues, written as strings such as "0" and "1"; names such as "speaker-1" are rejected. You can assign up to 32 speakers.

Terminal window
curl --request POST \
https://api.chamelaion.com/api/v1/video-translate/generate-with-media \
--header "Authorization: Bearer $CHAMELAION_API_KEY" \
--form "video=@/absolute/path/source-video.mp4;type=video/mp4" \
--form 'target_languages=["de"]' \
--form "source_srt=@/absolute/path/source-en.srt;type=application/x-subrip" \
--form 'config={"speaker_voices":{"0":"21m00Tcm4TlvDq8ikWAM","1":"AZnzlk1XvdvUeBnXmlld"}}'

Generation returns immediately:

{
"status": "success",
"request_id": "4c98dd00-a982-47d9-a8d6-e1f0b35a8944"
}

Retrieve the request by its UUID or exact reference_id. If several requests share a reference_id, the newest is returned.

Terminal window
curl --request GET \
https://api.chamelaion.com/api/v1/video-translate/requests/4c98dd00-a982-47d9-a8d6-e1f0b35a8944 \
--header "Authorization: Bearer $CHAMELAION_API_KEY"

A request moves through queued → uploading → processing → completed or failed. When it is completed, outputs is keyed by target language and contains video, audio, and SRT URLs. URLs are signed on every read and expire after one hour, so fetch the request again rather than storing them.

{
"id": "4c98dd00-a982-47d9-a8d6-e1f0b35a8944",
"reference_id": "translation-001",
"webhook_url": "https://example.com/webhooks/chamelaion",
"source_language": "en",
"target_languages": ["de", "fr"],
"disable_background_audio": false,
"disable_lip_sync": false,
"formality": false,
"config": {},
"status": "completed",
"created_at": "2026-10-09T10:00:00Z",
"started_at": "2026-10-09T10:00:01Z",
"finished_at": "2026-10-09T10:04:00Z",
"outputs": {
"de": {
"video": "https://storage.example/signed/de.mp4",
"audio": "https://storage.example/signed/de.wav",
"srt": "https://storage.example/signed/de.srt"
},
"fr": {
"video": "https://storage.example/signed/fr.mp4",
"audio": "https://storage.example/signed/fr.wav",
"srt": "https://storage.example/signed/fr.srt"
}
}
}

When a request fails, error_message explains why. Subtitle content is never returned; config shows only the file name and language of each supplied SRT.

List requests newest first, with pagination and optional filters:

Terminal window
curl --request GET \
"https://api.chamelaion.com/api/v1/video-translate/requests?limit=20&offset=0&status=completed&target_language=de" \
--header "Authorization: Bearer $CHAMELAION_API_KEY"
ParameterDescription
limitPage size, 1–100 (default: 20)
offsetNumber of results to skip (default: 0)
reference_idExact reference_id match
statusqueued, uploading, processing, completed, or failed
source_languageExplicit or detected source language
target_languageRequests that include this target language
created_fromCreated at or after this RFC 3339 timestamp, for example 2026-10-01T00:00:00Z
created_toCreated at or before this RFC 3339 timestamp

The response has a data array and a pagination object with limit, offset, and total.

Set webhook_url to a public HTTPS endpoint. CHAMELAION sends one JSON POST when the request reaches completed or failed:

{
"id": "5b0e7f7c-3c1e-4a5e-9f5d-0c6f1f0e2a11",
"type": "video_translate.completed",
"created_at": "2026-10-09T10:04:00Z",
"data": {
"id": "4c98dd00-a982-47d9-a8d6-e1f0b35a8944",
"status": "completed",
"outputs": { "de": { "video": "https://...", "audio": "https://...", "srt": "https://..." } }
}
}
  • data has the same fields as GET /v1/video-translate/requests/{id}, without webhook_url.
  • The X-Chamelaion-Event header is video_translate.completed or video_translate.failed.
  • The X-Chamelaion-Delivery header matches the body’s id and stays the same across retries. Use it to deduplicate.
  • Each attempt times out after 10 seconds. Network errors, HTTP 429, and HTTP 5xx are retried, for up to three attempts in total.
  • Redirects are not followed. Redirects and other non-2xx responses (except 429) are not retried.
  • Webhooks are not signed. Before acting on an event, confirm it by retrieving the request from the API.

Return a 2xx response quickly and process the event asynchronously. Delivery is best effort, so poll the request as a fallback.

ItemLimit
Target languages per request10
Video size (URL or upload)2 GiB
JSON request body8 MiB
SRT file1 MiB and 5,000 cues each, 5 MiB per request
Speakers in speaker_voices32
webhook_url length2,048 bytes

Source and target support differ. Use canonical lowercase codes; regional English and Portuguese codes are normalized where supported.

Source languages (84): af, am, ar, as, az, be, bg, bn, bs, ca, cs, cy, da, de, el, en, es, et, fa, fi, fil, fr, gl, gu, ha, he, hi, hr, hu, hy, id, is, it, ja, jv, ka, kk, km, kn, ko, lb, ln, lo, lt, lv, mi, mk, ml, mn, mr, ms, mt, my, ne, nl, no, oc, or, pa, pl, ps, pt, ro, ru, sd, si, sk, sl, sn, so, sr, sv, sw, ta, te, tg, th, tr, uk, ur, uz, vi, yo, zh.

Expressive target languages (91): af, am, ar, as, az, be, bg, bn, bs, ca, ceb, ckb, cs, cy, da, de, el, en, es, et, fa, ff, fi, fil, fr, ga, gl, gu, ha, he, hi, hr, hu, hy, id, is, it, ja, jv, ka, kk, kn, ko, ky, lb, lg, ln, lo, lt, lv, mi, mk, ml, mn, mr, ms, mt, my, ne, nl, no, ny, oc, or, pa, pl, ps, pt, ro, ru, sd, sk, sl, sn, so, sr, sv, sw, ta, te, tg, th, tr, uk, ur, uz, vi, yo, yue, zh, zu.

Classic target languages (29): ar, bg, zh, hr, cs, da, nl, en, fi, fr, de, el, hi, id, it, ja, ko, ms, fil, pl, pt, ro, ru, sk, es, sv, ta, tr, uk.

The aliases en-gb, en-us, pt-br, pt-pt, and tl are accepted and normalized to their base language. jw is accepted as a legacy alias for jv.

The official TypeScript, Python, and Go SDKs support Video Translate starting with v1.1.0. Each client reads your key from CHAMELAION_API_KEY when you don’t pass one.

import Chamelaion from "chamelaion";
const client = new Chamelaion(); // reads CHAMELAION_API_KEY
const job = await client.videoTranslate.generate({
source_language: "en",
target_languages: ["kn"],
model: "expressive",
inputs: [{ type: "video", url: "https://storage.googleapis.com/chamelaion-test-media/video.mp4" }],
});
const result = await client.videoTranslate.requests.retrieve(job.request_id);
from chamelaion import Chamelaion
client = Chamelaion() # reads CHAMELAION_API_KEY
job = client.video_translate.generate(
source_language="en",
target_languages=["kn"],
model="expressive",
inputs=[{"type": "video", "url": "https://storage.googleapis.com/chamelaion-test-media/video.mp4"}],
)
result = client.video_translate.requests.retrieve(job.request_id)
ctx := context.Background()
client := chamelaion.NewClient() // reads CHAMELAION_API_KEY
job, err := client.VideoTranslate.Generate(ctx, chamelaion.VideoTranslateGenerateParams{
SourceLanguage: chamelaion.String("en"),
TargetLanguages: []string{"kn"},
Model: chamelaion.VideoTranslateModelExpressive,
Inputs: []chamelaion.VideoTranslateGenerateParamsInput{
{Type: "video", URL: "https://storage.googleapis.com/chamelaion-test-media/video.mp4"},
},
})
if err != nil {
log.Fatal(err)
}
result, err := client.VideoTranslate.Requests.Get(ctx, job.RequestID)
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Status)

The SDKs support Video Translate starting with v1.1.0; the product-facing model field is available in v2.0.0. See the Video Translate API reference for complete request and response schemas and SDK methods.