API docs

Programmatic dubbing pipeline · beta access by request · Updated October 15, 2026

State of the API: everything below is the live surface behind our own Studio app, exposed in closed beta. During the open beta, programmatic API keys are issued by request — email [email protected] with your use case and volume. Webhooks and per-key rate limits are on the near-term roadmap and marked planned below; we won't document things that don't run yet.

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/uploads

Body {name, type, size} (≤ 500 MB). Returns a storage key and a presigned uploadUrl. Upload with a raw PUT — no credentials in that request.

POST/jobs

Creates a dubbing job. Fields:

FieldMeaning
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.
langsArray 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).
styleCaption preset: clean · bold_pop · word_highlight · bilingual. Applies to burned-in subs.
glossaryOptional 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).

GET/jobs/:id

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.

POST/jobs/:id/redub

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.

POST/jobs/:id/retry

Re-runs failed/cancelled stages only. Passed QC work is never re-rendered or re-billed.

GET/jobs/:id/bundle

One 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/glossary

Workspace-level term lists persist across jobs (CRUD + payload above).

Credits & billing model

UnitCost
Voice dub, per language1 credit per finished minute
Subtitles-only delivery0.4 credit per finished minute
Burned-in subtitle removal+0.5 credit per finished minute, billed once per job regardless of language count
Line redub1 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 · codeMeaning
400 invalid_requestMalformed payload (field name in message).
401 unauthenticatedMissing/expired session or key.
402 insufficient_creditsQuote exceeds balance — top up or reduce scope.
403 not_approvedAccount hasn't passed open-beta review yet.
404 not_foundUnknown job id or expired media key.
409 job_conflictAnother mutating action on the same job is in flight.
500 / timeoutOur fault — the retry rule above applies, no charge.

Limits & roadmap