Text to speech API for video voiceover

Send your timed script with a video or audio recording, and generate speech aligned to its timeline. Choose AI voices from the voice library or a voice clone, in 135+ language and regional options, and download the voiceover, the video and subtitles from the same project.
Script to voiceover
AI voices and voice clones
REST + Python SDK
script in, voiceover out
OAuth 2.0
# 1. send your script as timed segments - one speaker per line
curl -X POST https://api.rask.ai/v2/transcriptions \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"segments": [
    {"speaker": "SPEAKER_00", "start": "00:00:00,500", "end": "00:00:04,800",
     "src": {"text": "Welcome to the new dashboard.", "lang": "en"},
     "dst": {"text": "Bienvenido al nuevo panel.", "lang": "es-mx"}}
  ]}'

# 2. voice the script over your video
curl -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\", \"transcript_id\": \"$TRANSCRIPT_ID\"}"
GET /v2/projects/{project_id}
voiceover links
# When status is merging_done, read the voiceover links
curl -s https://api.rask.ai/v2/projects/$ID -H "Authorization: Bearer $TOKEN" \
  | jq '{status, voiceover, translated_audio, translated_video}'
Used by global teams
Capabilities

Everything the text to speech API does for video

Turn a written script into voiceover that fits the picture: the right voice for each speaker, timing from your segments, background audio, subtitles and translation in one project. Add optional lip-sync, billed separately.

Your script, spoken

Create a transcript from your own text segments or an SRT file, and the API generates speech for exactly that script in the target language.

Voice library

Every target locale has AI voice presets with a set gender. List them for a project with the voices endpoint and assign one to each speaker by voice ID.

Custom voices and voice clones

Use a saved Custom Voice Clone as a consistent brand voice, or keep an on-screen speaker's own voice with Instant Voice Clone, in supported voice cloning languages.

Timed to the picture

Each segment has a start and an end time, so every line of speech lands where it belongs in the video.

Character voices and dialogue

Assign a speaker to each line and a voice to each speaker, so a dialogue or a cast of character voices stays clear and consistent.

135+ language and regional options

Write the script in one language and voice it in another: Rask translates it, and AI voices are available for every target locale.

Voice-only audio track

On eligible plans, download the spoken audio as a WAV track without background, ready for your own edit, or the full mix and the finished video.

Edit a line, regenerate a line

Change the text of one segment or the voice of one speaker and regenerate. Nobody records anything again, and only the changed segments are billed.

Scale without limits

No rate limits, no concurrency quota, no per-key throttle. Voice long form content and full video catalogues in parallel.
See it in action

Hear one picture voiced in five languages

The same clip voiced in English, French, German, Portuguese and Spanish, timed to the same picture, with the original background audio intact.
EN flag
En
FR flag
Fr
DE flag
De
PT flag
Pt
ES flag
Es
Workflow

Three steps from script to voiceover

Creating the project starts speech generation for your script. Use the /generate endpoint after you change text or voices.
1

Upload video or audio

Upload the video or audio recording your voiceover belongs to, using a file or a supported media URL. Its timeline provides the timing for your script.

POST /api/library/v1/media/link
2

Send your script

Create a transcript from text segments with timestamps and speakers, or from an SRT file, then create the project with its transcript_id and a target language.

POST /v2/transcriptions
3

Choose voices and download

List the voices, assign a preset or a clone to each speaker, regenerate if needed, then download the voiceover, the video and the subtitle files.

GET /v2/projects/{id}/voices
Processing time varies by project. Speech is generated for the whole project and delivered as files, so this API suits published video rather than live conversation.
Built around you

Need a voice that is not in the library? Talk to our team

A brand voice, a language outside the catalogue, higher throughput or your own delivery method: when a voiceover integration needs something outside the public catalogue, our team reviews your requirements and the available options.

Languages and voices

Need a language or voice outside the public catalogue? Talk to our team about your requirements and the available options.

Delivery and integration

Webhooks, push into your own queue, delivery straight to your S3, custom endpoints. Tell us how your pipeline expects to be fed.

Volume and throughput

Batch sizes, target languages per action and processing priority are all contract terms, not fixed product limits.

Security and hosting

Data residency, SSO and SAML, retention rules and security review support are handled as part of enterprise onboarding.
Use cases

Who uses a text to speech API for video

Platforms with video inside

LMS and customer-education platforms, creator and video platforms, webinar and virtual event tools, video hosting and workflow SaaS, digital adoption platforms, live shopping. Let users type or upload a script and get voiceover for their videos in multiple languages, without leaving your product.

Localization and production agencies

Voice approved scripts for client videos in AI voices or a client's custom voice, and deliver the voice-only WAV for your own mix. Update a line after review and regenerate only that segment.

In-house continuous video production

International retail and e-commerce, global franchises, media publishers, corporate universities. Produce voiceover for training, product and marketing videos from a written script, and update the text when the product changes.
Customer stories

Real teams, measurable results

How companies localize video with Rask, in their own numbers.
arrow
arrow
Code

Text to speech API code examples

One complete example in each language: send a script as timed segments, create the project, pick a voice from the library, regenerate and download the voiceover.
# 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)

    script = await client.create_transcription(data=schemas.TranscriptionCreate(segments=[
        schemas.SegmentCreate(speaker="SPEAKER_00", start="00:00:00,500", end="00:00:04,800",
            src=schemas.SegmentTextCreatePatch(text="Welcome to the new dashboard.", lang="en"),
            dst=schemas.SegmentTextCreatePatch(text="Bienvenido al nuevo panel.", lang="es-mx")),
    ]))

    job = await wait(client, await client.create_project(data=schemas.ProjectCreate(
        video_id=VIDEO_ID, dst_lang="es-mx", transcript_id=script.id)))

    # pick a female AI voice preset from the library for SPEAKER_00
    voices = await client.get_project_voices(project_id=job.id)
    preset = next(v for v in voices if v.gender == "female")
    await client.patch_project(project_id=job.id, data=schemas.ProjectPatch(voice={**job.voice, "SPEAKER_00": preset.id}))

    job = await wait(client, await client.generate_project(project_id=job.id))
    print(job.voiceover, job.translated_video)

asyncio.run(main())
github.com/braskai/rask-sdk
async, typed models
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

script = requests.post(f"{API}/v2/transcriptions", headers=h, json={"segments": [
        {"speaker": "SPEAKER_00", "start": "00:00:00,500", "end": "00:00:04,800",
         "src": {"text": "Welcome to the new dashboard.", "lang": "en"},
         "dst": {"text": "Bienvenido al nuevo panel.", "lang": "es-mx"}},
    ]}).json()

pid = requests.post(f"{API}/v2/projects", headers=h, json={
    "video_id": VIDEO_ID, "dst_lang": "es-mx", "transcript_id": script["id"]}).json()["id"]
project = wait(pid)

voices = requests.get(f"{API}/v2/projects/{pid}/voices", headers=h).json()
preset = next(v for v in voices if v["gender"] == "female")
requests.patch(f"{API}/v2/projects/{pid}", headers=h,
               json={"voice": {**project["voice"], "SPEAKER_00": preset["id"]}})
requests.post(f"{API}/v2/projects/{pid}/generate", headers=h)
print(wait(pid)["voiceover"])
requests + polling
no SDK required
// 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; };

const script = await call('POST', '/v2/transcriptions', { segments: [
  { speaker: 'SPEAKER_00', start: '00:00:00,500', end: '00:00:04,800',
    src: { text: 'Welcome to the new dashboard.', lang: 'en' },
    dst: { text: 'Bienvenido al nuevo panel.', lang: 'es-mx' } },
] });

const { id } = await call('POST', '/v2/projects', { video_id: VIDEO_ID, dst_lang: 'es-mx', transcript_id: script.id });
const project = await wait(id);

const voices = await call('GET', `/v2/projects/${id}/voices`);
const preset = voices.find((v) => v.gender === 'female');
await call('PATCH', `/v2/projects/${id}`, { voice: { ...project.voice, SPEAKER_00: preset.id } });
await call('POST', `/v2/projects/${id}/generate`);
console.log((await wait(id)).voiceover);
fetch, Node 18+
plain HTTP
# 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. your script as an SRT file in the target language
TRANSCRIPT_ID=$(curl -s -X POST "https://api.rask.ai/v2/transcriptions/srt?dst_lang=es-mx" \
  -H "Authorization: Bearer $TOKEN" -F "dst=@script_es-mx.srt" | jq -r .id)

# 3. voice it over the video
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\", \"transcript_id\": \"$TRANSCRIPT_ID\"}" | jq -r .id)

# 4. when status is merging_done, read the voiceover links
curl -s https://api.rask.ai/v2/projects/$ID -H "Authorization: Bearer $TOKEN" \
  | jq '{status, voiceover, translated_video}'
POST /v2/transcriptions/srt
script from an SRT file
<?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']];

$script = $json($http->post('/v2/transcriptions', ['headers' => $h, 'json' => ['segments' => [[
    'speaker' => 'SPEAKER_00', 'start' => '00:00:00,500', 'end' => '00:00:04,800',
    'src' => ['text' => 'Welcome to the new dashboard.', 'lang' => 'en'],
    'dst' => ['text' => 'Bienvenido al nuevo panel.', 'lang' => 'es-mx'],
]]]]));

$p = $json($http->post('/v2/projects', ['headers' => $h, 'json' => [
    'video_id' => $videoId, 'dst_lang' => 'es-mx', 'transcript_id' => $script['id']]]));

while ($p['status'] !== 'merging_done') {
    sleep(10);
    $p = $json($http->get("/v2/projects/{$p['id']}", ['headers' => $h]));
}
echo $p['voiceover'];
Guzzle 7
plain HTTP
Python is the official SDK. The Node, PHP and cURL tabs are plain HTTP examples against the same endpoints.
Progress

How a voiceover project reports progress

Speech generation runs as a project with documented statuses, so you can show real progress even for long form content. You only need to act on three groups.

Success, stop here

merging_done
The voiceover is complete. Fetch the project once more to retrieve the download links available for your project.

In progress, keep polling

created
uploading
transcription_started
separate_background_started
determine_speakers_started
translation_started
voiceover_started
merging_started
Plus the matching _done states. These map cleanly onto a staged progress UI.

Failure, stop and report

failed
upload_failed
transcription_failed
translation_failed
voiceover_failed
merging_failed
no_audio
no_words
forbidden_link
no_audio, no_words and forbidden_link are specific enough to show directly to your own user.
Voice options in a project, es-mx
GET /v2/projects/{project_id}/voices
{"label": "Renata",      "gender": "female", "sample_src": "https://..."}   AI voice preset
{"label": "Gerardo",     "gender": "male",   "sample_src": "https://..."}   AI voice preset
{"label": "Maria Lopez", "gender": "auto",   "sample_src": "https://..."}   custom voice clone
{"label": "Voice Clone", "gender": "auto",   "sample_src": null}            instant voice clone

Or skip polling entirely

Point us at a webhook endpoint and every state transition arrives as a POST, so your queue reacts to each change the moment it happens. Webhook delivery is part of enterprise onboarding.
Read the docs
preserveAspectRatio="xMidYMid meet" aria-hidden="true" role="img">
Output

Voiceover audio, video and subtitles

Download the video with the new voiceover and subtitles in SRT and VTT. On eligible plans, you can also download the spoken audio on its own as WAV, or mixed with the original background audio.
Field
Format
What it is
translated_video
MP4
The video with the generated voiceover, ready to publish
voiceover
WAV
Generated speech only, no background, for your own edit
translated_audio
WAV
Translated speech mixed with the original background audio
translation_srt_path
.srt
Subtitles in the target language
translation_vtt_path
.vtt
Same subtitles as WebVTT, for web players
original_video
MP4
Your source file as stored, for reference
Control

Change a line or a voice, regenerate only that part

Your script is stored as segments. Edit the text of one line or change the voice of one speaker, regenerate, and only the changed segments are billed, with a one-minute minimum per run.

Segment-level editing

Segment-level editing
Every project exposes its script as segments with timestamps, speakers and text, so a correction is one patch request.
Fetch the transcript and its segments
Patch the source text and we re-translate it
Patch the translated text directly to keep your own wording
Adjust timestamps, add segments, delete segments
Reassign the voice attached to any speaker

Glossaries for terminology

Glossaries for terminology
When Rask translates your script into other languages, a glossary keeps brand names and technical terms the same in every version, or in the original language on purpose.

A glossary covers one language pair and applies across all regional variants of that target language, so one Spanish glossary serves es-mx and es-es alike. The project records glossary_version, so later edits never silently change finished work.
Input

Supported file formats

Upload the video your voiceover belongs to in any supported format, or send a URL. Scripts come in as text segments through the API or as SRT files.

Video

7 formats
.mp4
.mov
.mkv
.avi
.webm
.m4v
.3gp

Audio

4 formats
.mp3
.wav
.flac
.m4a

Metadata before you spend

The media endpoint returns duration, file size, video codec, frame rate, resolution, audio codec, sample rate and channel layout. Validate a file and estimate cost in advance, because voiceover is billed by the minute of video, not per character.
Security and compliance

Enterprise grade security for scripts and voices

Brask Inc holds SOC 2 Type II and operates under GDPR, and publishes live control status in its Trust Center. Custom voice clones are created with the speaker's consent.

Certifications

SOC 2 Type II
GDPR
CAI and C2PA member

Encryption

TLS 1.2 in transit
AES-256 at rest
SSE-S3 managed keys
Key rotation at least every 12 months

Your content

Closed AI environment
Never used to train general models
Full export, no lock-in

Access

SSO and SAML
Role-based access control
OAuth 2.0 client credentials

Enterprise

Data residency options
Custom SLAs
Dedicated account manager

Voice rights

Synthetic voices with usage rights
Consent-based voice cloning
AI safety controls, human in the loop
Comparison

Rask API vs a voiceover pipeline you build yourself

A streaming text to speech API converts text into audio bytes for live use. Voiceover for published video also needs timing, a voice per speaker, mixing, subtitles and often translation. Here is the same voiceover, assembled two ways.
What you need
Rask API
Assembled from parts
A script timed to the video
Segments with start and end times
Your own alignment logic
A voice for each speaker or character
Voice map per project
Voice IDs managed per request
A consistent brand voice
Custom voice clones
A separate cloning vendor
The same script in other languages
Translation in the same project
A translation API plus new timing
Background music and effects
Mixed under the voiceover
Your own mixing step
Subtitles in .srt and .vtt
Included
Generated from your own timing data
A voice-only audio track
WAV on eligible plans
Audio chunks you join yourself
Changing one line
Regenerate the changed segments
Re-synthesize and re-mix the file
Rate limits
None
Whatever your provider enforces
Live voice agents with streaming
Use a streaming TTS API
Built for it
FAQ

Text to speech API: common questions

Can't find what you're looking for? Contact sales.

Does Rask have a text to speech API?

Can I use it for voice agents or contact centers?

Does the API support streaming audio output?

How do I send my script?

Which voices are available?

Can I use a custom voice?

Which languages are supported?

Do you support SSML tags or custom pronunciations?

Can I control emotion and expressive delivery?

Do I need a video to generate speech?

Is pricing per character?

Is there a free tier or free credits?

How do I get API access and an API key?

Start dubbing in one afternoon

Make your first request today, and talk to us when you need volume terms or a language nobody else has.