# 1. create the dub - each speaker gets an Instant Voice Clone by default
curl -X POST https://api.rask.ai/v2/projects \
-H "Authorization: Bearer $TOKEN" \
-d '{"video_id": "b8f7835d-e8c9-4ff4-8e34-5c336d818319", "dst_lang": "es-mx"}'
# 2. list the voices available in this project
curl https://api.rask.ai/v2/projects/$ID/voices \
-H "Authorization: Bearer $TOKEN"
# "label": "Voice Clone", "gender": "auto" instant clone
# "label": "Maria Lopez", "sample_src": "https://..." your custom clone
# 3. assign your custom clone - include every speaker in the map
curl -X PATCH https://api.rask.ai/v2/projects/$ID \
-H "Authorization: Bearer $TOKEN" \
-d '{"voice": {"SPEAKER_00": "<custom_voice_id>", "SPEAKER_01": "<voice_id>"}}'# 4. re-dub with the new voices, then poll until merging_done
curl -X POST https://api.rask.ai/v2/projects/$ID/generate \
-H "Authorization: Bearer $TOKEN"
while :; do
curl -s https://api.rask.ai/v2/projects/$ID -H "Authorization: Bearer $TOKEN" | jq .status
sleep 10
done



Send a file as multipart form data, or post a link from YouTube, Google Drive, S3, Vimeo or any direct URL. The speech in this video is the voice sample for each Instant Voice Clone.
Pass the media id as video_id and a target language. Each detected speaker receives an Instant Voice Clone in supported languages, and the dub starts immediately.
List voices for the project, assign a custom clone or a preset to any speaker, then call /generate and download the files when the dub is complete.
# pip install git+ssh://[email protected]/braskai/rask-sdk.git@main
import asyncio
from rask_sdk import clients, enums, schemas
async def wait(client, job):
while job.status is not enums.ProjectStatus.MERGING_DONE:
await asyncio.sleep(10)
job = await client.get_project(project_id=job.id)
return job
async def main():
client = clients.RaskSDKClient(client_id=CLIENT_ID, client_secret=CLIENT_SECRET)
video = await client.create_media_link(data=schemas.MediaCreateLink(link="https://youtu.be/..."))
while video.status is not enums.MediaStatus.READY:
await asyncio.sleep(5)
video = await client.get_media(media_id=video.id)
# first dub: every speaker gets an Instant Voice Clone
job = await wait(client, await client.create_project(
data=schemas.ProjectCreate(video_id=video.id, dst_lang="es-mx")))
# assign a custom clone to SPEAKER_00, keep the other speakers as they are
voices = await client.get_project_voices(project_id=job.id)
custom = next(v for v in voices if v.label == "Maria Lopez")
voice_map = {**job.voice, "SPEAKER_00": custom.id}
await client.patch_project(project_id=job.id, data=schemas.ProjectPatch(voice=voice_map))
job = await wait(client, await client.generate_project(project_id=job.id))
print(job.translated_video, job.voiceover)
asyncio.run(main())import time, requests
AUTH = "https://rask-prod.auth.us-east-2.amazoncognito.com/oauth2/token"
API = "https://api.rask.ai"
token = requests.post(AUTH, auth=(CLIENT_ID, CLIENT_SECRET),
data={"grant_type": "client_credentials"}).json()["access_token"]
h = {"Authorization": f"Bearer {token}"}
def wait(pid):
while (p := requests.get(f"{API}/v2/projects/{pid}", headers=h).json())["status"] != "merging_done":
time.sleep(10)
return p
video = requests.post(f"{API}/api/library/v1/media/link", headers=h, json={"link": "https://youtu.be/..."}).json()
while video["status"] != "ready":
time.sleep(5)
video = requests.get(f"{API}/api/library/v1/media/{video['id']}", headers=h).json()
pid = requests.post(f"{API}/v2/projects", headers=h,
json={"video_id": video["id"], "dst_lang": "es-mx"}).json()["id"]
project = wait(pid)
voices = requests.get(f"{API}/v2/projects/{pid}/voices", headers=h).json()
custom = next(v for v in voices if v["label"] == "Maria Lopez")
voice_map = {**project["voice"], "SPEAKER_00": custom["id"]} # every speaker stays in the map
requests.patch(f"{API}/v2/projects/{pid}", headers=h, json={"voice": voice_map})
requests.post(f"{API}/v2/projects/{pid}/generate", headers=h)
print(wait(pid)["translated_video"])// no dependencies, Node 18+ global fetch
const API = 'https://api.rask.ai';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const auth = await fetch('https://rask-prod.auth.us-east-2.amazoncognito.com/oauth2/token', {
method: 'POST',
headers: { Authorization: 'Basic ' + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`) },
body: new URLSearchParams({ grant_type: 'client_credentials' }),
}).then((r) => r.json());
const h = { Authorization: `Bearer ${auth.access_token}`, 'Content-Type': 'application/json' };
const call = (method, path, body) => fetch(API + path, { method, headers: h, body: body && JSON.stringify(body) }).then((r) => r.json());
const wait = async (id) => { let p; while ((p = await call('GET', `/v2/projects/${id}`)).status !== 'merging_done') await sleep(10000); return p; };
let video = await call('POST', '/api/library/v1/media/link', { link: 'https://youtu.be/...' });
while (video.status !== 'ready') { await sleep(5000); video = await call('GET', `/api/library/v1/media/${video.id}`); }
const { id } = await call('POST', '/v2/projects', { video_id: video.id, dst_lang: 'es-mx' });
const project = await wait(id);
const voices = await call('GET', `/v2/projects/${id}/voices`);
const custom = voices.find((v) => v.label === 'Maria Lopez');
await call('PATCH', `/v2/projects/${id}`, { voice: { ...project.voice, SPEAKER_00: custom.id } });
await call('POST', `/v2/projects/${id}/generate`);
console.log((await wait(id)).translated_video);# 1. token (valid 1 hour - cache and reuse it)
TOKEN=$(curl -s -X POST https://rask-prod.auth.us-east-2.amazoncognito.com/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" -d "grant_type=client_credentials" | jq -r .access_token)
# 2. create the dub - Instant Voice Clones are assigned by default
ID=$(curl -s -X POST https://api.rask.ai/v2/projects -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" -d "{\"video_id\": \"$VIDEO_ID\", \"dst_lang\": \"es-mx\"}" | jq -r .id)
# 3. after merging_done: read the current voice map and the voice options
curl -s https://api.rask.ai/v2/projects/$ID -H "Authorization: Bearer $TOKEN" | jq .voice
curl -s https://api.rask.ai/v2/projects/$ID/voices -H "Authorization: Bearer $TOKEN" | jq '.[] | {id, label, gender}'
# 4. assign voices for every speaker, then re-dub
curl -s -X PATCH https://api.rask.ai/v2/projects/$ID -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" -d '{"voice": {"SPEAKER_00": "<custom_voice_id>", "SPEAKER_01": "<voice_id>"}}'
curl -s -X POST https://api.rask.ai/v2/projects/$ID/generate -H "Authorization: Bearer $TOKEN"<?php
use GuzzleHttp\Client;
$http = new Client(['base_uri' => 'https://api.rask.ai']);
$json = fn($r) => json_decode($r->getBody(), true);
$auth = $json((new Client)->post('https://rask-prod.auth.us-east-2.amazoncognito.com/oauth2/token',
['auth' => [$clientId, $clientSecret], 'form_params' => ['grant_type' => 'client_credentials']]));
$h = ['Authorization' => 'Bearer ' . $auth['access_token']];
$wait = function ($id) use ($http, $h, $json) {
do { sleep(10); $p = $json($http->get("/v2/projects/$id", ['headers' => $h])); }
while ($p['status'] !== 'merging_done');
return $p;
};
$id = $json($http->post('/v2/projects', ['headers' => $h,
'json' => ['video_id' => $videoId, 'dst_lang' => 'es-mx']]))['id'];
$project = $wait($id);
$voices = $json($http->get("/v2/projects/$id/voices", ['headers' => $h]));
$custom = current(array_filter($voices, fn($v) => $v['label'] === 'Maria Lopez'));
$map = array_merge($project['voice'], ['SPEAKER_00' => $custom['id']]);
$http->patch("/v2/projects/$id", ['headers' => $h, 'json' => ['voice' => $map]]);
$http->post("/v2/projects/$id/generate", ['headers' => $h]);
echo $wait($id)['translated_video']; 0s created
11s transcription_started
87s translation_started
99s voiceover_started
154s merging_started
165s merging_done

es-mx and es-es alike. The project records glossary_version, so later edits never silently change finished work.Yes. The Rask voice cloning API clones each speaker's voice as part of dubbing a video. Create a project with a target language and every speaker receives an Instant Voice Clone in supported languages. You can also assign a Custom Voice Clone you created in the Rask app to any speaker.
Instant Voice Clone uses the speakers' voices from your source video for supported target languages. For a reusable Custom Voice Clone, create it in the Rask app with the speaker's consent, then assign it through the API. Results depend on the source audio and the selected language and voice.
Instant Voice Clone is created automatically from the speech in the video you dub, with no short audio samples to record. Custom Voice Clone is trained from audio samples you upload once, saved to your voice library and reused in any project by its voice_id. In the voices list, an Instant Voice Clone has the label "Voice Clone" and gender "auto".
Creating a Custom Voice Clone is available in the Rask web platform. Once the clone is saved, retrieve its voice_id with the get project voices endpoint and assign it to a speaker through the API.
Upload 1 to 10 minutes of audio or video, up to 10 files of up to 10 MB each, in MP4, MOV, WEBM, MKV, MP3, M4A or WAV, or paste a YouTube or Google Drive link. For best results, use one speaker with a consistent speaking style, recorded in a quiet room with a good microphone and no background noise.
Voice cloning supports 32 base languages and their supported regional variants. Regional variants use the base cloning model: for example, UK English text uses the US English voice model. For other target languages, choose an AI voice preset. See the API language catalogue for the full list.
The API dubs both video and audio recordings, including audio-only podcasts and interviews. To use your own wording, edit the translated text segment by segment, or create the transcript from your own .srt before you create the project, and the cloned voice speaks your text. The input is always a recording, so for text-only voiceovers a text to speech API is the better fit.
Get the voice options with GET /v2/projects/{id}/voices, then send PATCH /v2/projects/{id} with a voice map that includes every speaker, the changed one and the unchanged ones. Call /generate to re-dub. Re-dubbing is billed on the combined duration of changed segments, with a one-minute minimum per charged run.
Creator Pro plans include up to 3 custom voices, Business plans up to 10 shared team voices, and Enterprise plans a custom voice library.
Yes. Custom voice clones are created with the speaker's consent, and you should only dub videos whose speakers have agreed to it. Rask uses consent-based voice cloning and AI safety controls, and your audio is never used to train general models.
The clone replicates the voice identity of the speaker, including timbre and pitch, so they sound like themselves in another language. Emotional tone, cadence and rhythm follow the source audio and the translated script, so clear, expressive source speech gives the best results.
You can publish dubbed videos with cloned voices in your commercial content when you have the rights to the source video and the consent of the speakers. Check the Rask Terms of Service for the details that apply to your plan.
Voice cloning is part of dubbing and has no separate fee: API usage is billed per minute of video, rounded up to the next whole minute, from the same minutes pool as the Rask app. Minutes beyond a plan cost $3 per minute. Re-dubbing after a voice change is billed only for the changed segments. Start with a free trial, no credit card required.