API docs
Programmatic dubbing pipeline · beta access by request · Updated October 15, 2026
Quick start
Base URL https://app.voxtakes.com/api. Auth today is your browser session cookie; beta key-holders get an Authorization: Bearer token. A minimal dubbing run takes three calls:
# 1. reserve an upload slot and PUT your file to object storage
curl -X POST https://app.voxtakes.com/api/uploads \
-H 'content-type: application/json' \
-d '{"name":"launch.mp4","type":"video/mp4","size":52428800}'
# -> {"key":"users/<uid>/…/launch.mp4","uploadUrl":"https://… (presigned PUT)"}
curl -X PUT --upload-file launch.mp4 "<uploadUrl>"
# 2. create the job
curl -X POST https://app.voxtakes.com/api/jobs \
-H 'content-type: application/json' \
-d '{"src":{"kind":"upload","key":"users/…/launch.mp4"},
"langs":["es","de"],
"delivery":{"subs":true,"dub":true,"clean":true},
"style":"bold_pop",
"glossary":[{"term":"ZELOS","keep":true}]}'
# -> {"id":"a91f…","status":"queued","credits_preauth":6800}
# 3. poll progress
curl https://app.voxtakes.com/api/jobs/a91f…
Endpoints
POST/uploadsBody {name, type, size} (≤ 500 MB). Returns a storage key and a presigned uploadUrl. Upload with a raw PUT — no credentials in that request.
Creates a dubbing job. Fields:
| Field | Meaning |
|---|---|
| src | {kind:"upload", key} or {kind:"url", url} (YouTube). URL pull is convenience; uploads are the reliable path — upstream platforms sometimes bot-check server-side fetches. |
| langs | Array of targets from en es de fr pt ja ko zh (ar beta — ask). Source language is auto-detected. |
| delivery | {subs: bool, dub: bool, clean: bool} — subtitles only, voice dub, and/or both; clean:true first erases burned-in captions from the picture (one pass shared by all languages). |
| style | Caption preset: clean · bold_pop · word_highlight · bilingual. Applies to burned-in subs. |
| glossary | Optional per-job term locks: {term, translations?: {lang→text}, keep?: bool}. keep:true = verbatim in all languages. |
Response includes credits_preauth (the estimate held against your balance; final billing is per actual finished minute).
Job state machine. status ∈ queued → running → awaiting_review → done (plus failed / cancelled). While running you get a stage timeline per language:
clean → asr → translate:<lang> → tts_qc:<lang> → mix:<lang> → bundle
Each tts_qc line carries a machine quality score (0–1) computed by re-transcribing the rendered audio — lines scoring low are flagged for review instead of silently shipped. When status:"awaiting_review", results[lang].lines exposes every sentence with timecode, translation, score and audio URL.
Line-level fixes without re-rendering anything else:
-d '{"lang":"es","edits":[
{"line_id":7,"text":"nueva copia"},
{"line_id":12,"seed":"re-roll"},
{"line_id":20,"voice":"alt_02"}]}'
Billed as 1 credit per re-recorded line (or the changed line's duration — whichever model your plan uses is shown on the quote in the response). A/B is retained: you can pull both takes and compare before replacing the master. If the parent job used clean, the erased master is reused — you are never billed twice for removal.
Re-runs failed/cancelled stages only. Passed QC work is never re-rendered or re-billed.
GET/jobs/:id/bundleOne streamed zip per approved job: every language's MP4 + SRT/VTT + per-line audio + term-hit report. Download promptly — media auto-deletes 7 days after the job.
GET/glossary · POST/glossaryWorkspace-level term lists persist across jobs (CRUD + payload above).
Credits & billing model
| Unit | Cost |
|---|---|
| Voice dub, per language | 1 credit per finished minute |
| Subtitles-only delivery | 0.4 credit per finished minute |
| Burned-in subtitle removal | +0.5 credit per finished minute, billed once per job regardless of language count |
| Line redub | 1 credit per changed line; failed-QC re-dos are free |
1 credit-minute ≈ $0.48 on Creator pricing. Credits never expire. Overage is $0.89 / finished minute.
Errors
| Status · code | Meaning |
|---|---|
400 invalid_request | Malformed payload (field name in message). |
401 unauthenticated | Missing/expired session or key. |
402 insufficient_credits | Quote exceeds balance — top up or reduce scope. |
403 not_approved | Account hasn't passed open-beta review yet. |
404 not_found | Unknown job id or expired media key. |
409 job_conflict | Another mutating action on the same job is in flight. |
500 / timeout | Our fault — the retry rule above applies, no charge. |
Limits & roadmap
- Per job: 60 min duration / 2 GB source; ≤ 8 target languages.
- Planned: webhook callbacks on stage/status transitions · API keys with scopes · bulk queue endpoint · higher parallelism for Studio accounts. Priorities move with beta demand — say what you need on your access request.