Subtitle API for translated SRT and VTT files

Upload a video once and get subtitle files in SRT and WebVTT for every target language, timed to the spoken content. Correct any line through the API, then download updated files for your player, app or video editing software.
SRT and WebVTT
135+ language and regional options
REST + Python SDK
upload, create, download
OAuth 2.0
# 1. upload the video once - YouTube, Drive, S3, Vimeo or direct URL
curl -X POST https://api.rask.ai/api/library/v1/media/link \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"link": "https://example.com/onboarding.mp4", "name": "onboarding"}'

# 2. one project per subtitle language
for lang in es-mx fr-fr ja-jp; do
  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\": \"$lang\"}"
done
GET /v2/projects/{project_id}
.srt + .vtt
# When status is merging_done, download both subtitle files
P=$(curl -s https://api.rask.ai/v2/projects/$ID -H "Authorization: Bearer $TOKEN")
curl -s -o onboarding.es-mx.srt "$(echo $P | jq -r .translation_srt_path)"
curl -s -o onboarding.es-mx.vtt "$(echo $P | jq -r .translation_vtt_path)"
Used by global teams
Capabilities

Everything the subtitle API returns

Create translated SRT and WebVTT files from video or audio recordings, including podcasts and interviews. Choose a target language for each project and get subtitle files alongside the transcript, translation and dubbed content.

SRT and WebVTT files

Every finished project returns a .srt file and a .vtt file in the target language: SRT for video editing software and most platforms, WebVTT for web video playback.

Subtitles in another language

Remove language barriers for viewers in every market: create one project per target language, such as es-mx, pt-br or fr-ca, from the same upload. The source language is detected automatically.

Timed to the spoken content

Each subtitle follows a transcript segment with a start and an end time, so every line appears on screen while it is spoken.

Captions in the original language

The transcript holds the source text of every segment with timestamps. Convert it into an SRT or VTT file for same-language captions in a few lines of code.

Speaker labels for dialogue

Each transcript segment carries a speaker label, so you can add speaker identification to captions for interviews, panels and dialogue.

Edit a line before you publish

Correct the text or timing of any segment through the API and regenerate. Unclear words, names and accents get fixed once, in every format.

Consistent terms in every language

A glossary keeps product names and technical terms identical across all subtitle languages, or in the original language on purpose.

Subtitles and a dubbed version

The same project also returns the translated video and audio tracks, so subtitles and a dubbed version come from one upload.

Scale without limits

No rate limits, no concurrency quota, no per-key throttle. Subtitle your whole video library in every target language in parallel.
See it in action

One video, five language versions

The same clip in English, French, German, Portuguese and Spanish. Each language version comes with its own SRT and VTT subtitle files.
EN flag
En
FR flag
Fr
DE flag
De
PT flag
Pt
ES flag
Es
Workflow

Three requests from video upload to subtitle file

Creating the project starts transcription, translation and the dubbed version in one run. Use the /generate endpoint after you edit subtitle lines.
1

Upload your video

Send the video as a file, or post a link from YouTube, Google Drive, S3, Vimeo or any direct URL. One upload serves every subtitle language.

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

Create the project

Pass the media id as video_id and one target language per project. Projects for different languages run in parallel.

POST /v2/projects
3

Download the subtitle files

Read status until it reaches merging_done, then download the .srt and .vtt files and store them on your side.

GET /v2/projects/{project_id}
Processing time varies with video length, the number of speakers and the target language. In one observed run, a 3:47 video was finished in 165 seconds.
Built around you

Need a subtitle format or delivery that is not listed? Talk to our team

Another caption format, delivery to your own storage, a language outside the catalogue or higher throughput: our team reviews what your production workflow needs and the available options.

Languages and voices

Need subtitles in a language 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 subtitle API

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. Turn subtitles in every language into a feature of your video uploads.

Localization and production agencies

Deliver SRT and VTT files for every client language from one upload. Reviewers correct lines through the API, and the files update without anyone retiming them.

In-house continuous video production

International retail and e-commerce, global franchises, media publishers, corporate universities. Make training and product video content accessible to every market and to viewers who watch without sound.
Customer stories

Real teams, measurable results

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

Subtitle API code examples

One complete example in each language: upload a video, create a project per subtitle language, wait, then save the .srt and .vtt files or add them to an HTML5 player.
# pip install git+ssh://[email protected]/braskai/rask-sdk.git@main
import asyncio, urllib.request
from rask_sdk import clients, enums, schemas

LANGS = ["es-mx", "fr-fr", "ja-jp"]

async def subtitle(client, video_id, lang):
    job = await client.create_project(data=schemas.ProjectCreate(video_id=video_id, dst_lang=lang))
    while job.status is not enums.ProjectStatus.MERGING_DONE:
        await asyncio.sleep(10)
        job = await client.get_project(project_id=job.id)
    # links are presigned for one hour - save the files right away
    urllib.request.urlretrieve(job.translation_srt_path, f"video.{lang}.srt")
    urllib.request.urlretrieve(job.translation_vtt_path, f"video.{lang}.vtt")

async def main():
    client = clients.RaskSDKClient(client_id=CLIENT_ID, client_secret=CLIENT_SECRET)
    media = await client.create_media_link(data=schemas.MediaCreateLink(link="https://example.com/onboarding.mp4"))
    while media.status is enums.MediaStatus.PROCESSING:
        await asyncio.sleep(5)
        media = await client.get_media(media_id=media.id)
    await asyncio.gather(*(subtitle(client, media.id, l) for l in LANGS))

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}"}

pid = requests.post(f"{API}/v2/projects", headers=h,
                    json={"video_id": VIDEO_ID, "dst_lang": "de-de"}).json()["id"]
while (p := requests.get(f"{API}/v2/projects/{pid}", headers=h).json())["status"] != "merging_done":
    time.sleep(10)

# translated subtitles: download the files
open("video.de-de.vtt", "wb").write(requests.get(p["translation_vtt_path"]).content)

# original-language captions: build a WebVTT file from the transcript segments
segs = requests.get(f"{API}/v2/projects/{pid}/transcription", headers=h).json()["segments"]
cues = [f"{s['start'].replace(',', '.')} --> {s['end'].replace(',', '.')}\n{s['src']['text']}" for s in segs]
open("video.en.vtt", "w").write("WEBVTT\n\n" + "\n\n".join(cues) + "\n")
requests + polling
same-language captions
// no dependencies, Node 18+ global fetch
import { writeFile } from 'node:fs/promises';
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 langs = ['es-mx', 'pt-br', 'ko-kr'];
const tracks = await Promise.all(langs.map(async (dst_lang) => {
  let p = await call('POST', '/v2/projects', { video_id: VIDEO_ID, dst_lang });
  while (p.status !== 'merging_done') { await sleep(10000); p = await call('GET', `/v2/projects/${p.id}`); }
  const file = `subs/${dst_lang}.vtt`;
  await writeFile(file, await ((await fetch(p.translation_vtt_path)).text()));
  return `<track kind="subtitles" srclang="${dst_lang}" src="/${file}">`;
}));
console.log(tracks.join('\n'));   // paste inside your <video> element
fetch, Node 18+
HTML5 track elements
# 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 project for one subtitle language
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\": \"it-it\"}" | jq -r .id)

# 3. wait for merging_done
until [ "$(curl -s https://api.rask.ai/v2/projects/$ID -H "Authorization: Bearer $TOKEN" | jq -r .status)" = merging_done ]; do
  sleep 10
done

# 4. save both subtitle files
P=$(curl -s https://api.rask.ai/v2/projects/$ID -H "Authorization: Bearer $TOKEN")
curl -s -o video.it-it.srt "$(echo $P | jq -r .translation_srt_path)"
curl -s -o video.it-it.vtt "$(echo $P | jq -r .translation_vtt_path)"
download .srt and .vtt
shell script
<?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']];

foreach (['es-mx', 'tr-tr'] as $lang) {
    $p = $json($http->post('/v2/projects', ['headers' => $h, 'json' => [
        'video_id' => $videoId, 'dst_lang' => $lang]]));
    while ($p['status'] !== 'merging_done') {
        sleep(10);
        $p = $json($http->get("/v2/projects/{$p['id']}", ['headers' => $h]));
    }
    // presigned links, valid for one hour
    file_put_contents("video.$lang.srt", file_get_contents($p['translation_srt_path']));
    file_put_contents("video.$lang.vtt", file_get_contents($p['translation_vtt_path']));
}
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 subtitle project reports progress

Every project moves through documented statuses, so users who upload video in your app can follow the progress of each subtitle language. You only need to act on three groups.

Success, stop here

merging_done
The subtitle files are ready. Fetch the project once more to get fresh download links.

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.
Observed run, 3:47 source video, en → es-mx
GET /v2/projects/{project_id}
   0s  created
  11s  transcription_started
  87s  translation_started
  99s  voiceover_started
 154s  merging_started
 165s  merging_done

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

Subtitle files first, everything else alongside

Every finished project exposes both subtitle formats, the transcript segments behind them and the dubbed media. Download links are presigned and valid for one hour, so copy the files to your own storage.
Field
Format
What it is
translation_srt_path
.srt
Subtitles in the target language, for editing software and most video platforms
translation_vtt_path
.vtt
WebVTT subtitles for HTML5 video playback and web players
/transcription
JSON
Source text, translation, speaker label and timestamps for every segment
translated_video
MP4
The dubbed video, if you also publish a voiced version
translated_audio
WAV
Translated speech mixed with the original music and sound effects
original_video
MP4
Your source file as stored, for reference
Control

Fix a subtitle line, regenerate only that part

Subtitles come from transcript segments. Edit the text or the timing of one line, regenerate, and the subtitle files and the dubbed version update together. Billing covers the changed segments, with a one-minute minimum per run.

Segment-level editing

Segment-level editing
Every project exposes its transcript as addressable segments, so a wrong word or a late subtitle 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
Attach a glossary and brand names and technical terms read the same in the subtitles of every language, or stay 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 a supported video or audio recording, or use a supported media URL. Create a project for each target language and download its SRT and WebVTT 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 projects are billed by the minute of video.
Security and compliance

Security and compliance for your video content

Brask Inc holds SOC 2 Type II and operates under GDPR, and publishes live control status in its Trust Center for your security review.

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 subtitle pipeline you build yourself

Subtitles in another language need transcription, translation, timing and file export. Here is the same result, assembled two ways.
What you need
Rask API
Assembled from parts
Transcription with timestamps
Included
A speech to text API
Subtitles in another language
135+ language and regional options
A translation API plus re-timing
SRT and WebVTT export
Both formats in every project
Your own file writer
Consistent terminology
Glossaries
Custom post-processing
Correcting one line
One patch request, then regenerate
Edit every file by hand
A dubbed version of the same video
Included in the same project
A TTS vendor plus your own mixing
Rate limits
None
Whatever your providers enforce
Subtitles burned into the video
In the Rask web app, not yet in the API
Your own video rendering
Font, size and layout
Set in your video player
Set in your video player
FAQ

Subtitle API: common questions

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

Does Rask have a subtitle API?

Which subtitle formats does the API return?

Can I get subtitles in the original language?

Which languages are supported?

Can the API burn subtitles into the video?

Can I change the font, size or layout of the subtitles?

Do subtitles describe music and sound effects?

Are speakers identified?

How do I correct a subtitle line?

How long are the download links valid?

Can I bring my own subtitles?

How is the subtitle API billed?

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.