Skip to main content
A localization run does dub, lip-sync and on-screen translation in one job, under one price cap. The order is fixed, and each stage works on the previous result: on-screen renders over the lip-synced video when both are ordered. There are no other orders. You can start a run in two ways:
  • On an existing project: createLocalization, below.
  • On a new project: the localization block of createProject, shown in the Quickstart. Its dub stage is the auto-dub, priced on the processed media duration.

What you can order

Order lipsync, onscreen or both, on a video project. dub is optional and defaults to mode auto. A dub alone is createDub. The key needs dubbing:write and credits:spend, plus lipsync:write when lip-sync is ordered and onscreen:write when on-screen is ordered. The plan needs lipsync and lipsync_paid for lip-sync, lipsync_enhanced too for the Enhanced model, and onscreen for on-screen. A run never uses the free lip-sync run.

1. Estimate

total_minutes is the single total. details.stages prices each stage: A finished stage is not paid twice. A stage with a current result counts as succeeded, at no charge, and not_run_reason says so: Stages are judged in order, so a dub that runs again makes the lip-sync and on-screen after it run too. If every stage is reused, the job succeeds at once at 0 minutes. When the dub is reused, a lip-sync of another model than the current paid one answers 409 lipsync_already_done.

2. Start it

The request is checked as a whole: a total above the cap is 409 cost_changed, and a balance below it is 402 insufficient_balance. A key whose monthly spend limit cannot cover the cap gets 403 token_spend_limit_exceeded. Three cases answer 422 localization_combination_not_supported, and reason tells them apart. Nothing is charged:

3. Follow the run

The job’s stages has one entry per stage, each with its child job_id, its status (pending, running, succeeded, failed, skipped), reused, stage, cost and error. stage on the job itself is the running stage’s. A run cannot be canceled, and neither can the jobs of its stages. How the money moves. Nothing is reserved. Each stage is charged when it starts, under the one cap. cost on the run is what is held so far: the stages charged and not refunded. The cap you sent stays in params.expected_cost_minutes.

4. Get the video

The succeeded job’s result.final_output is an output of kind localized_video, the video that holds every ordered change, with its url. When available is false, url is null and unavailable_reason says why: for example not_in_plan when lip-sync is the last stage and the plan has no lipsync_download. The same output is in listProjectOutputs. result.notices carries the notices of the stages.

5. Resume a failed run

A run ends failed in one of two ways: In both, error.failed_stage names the stage and error.cause_code the cause. Stages that succeeded stay charged, and unreached ones were never charged. Remove the cause, for example by adding minutes, then price what is left. resume_job_id makes the estimate price the resume: stages that succeeded cost 0, with not_run_reason: already_succeeded.
Restarted stages are priced today, so the resume can cost more than the run had left. Compare its total_minutes with the price accepted for the run, less the failed job’s cost.minutes. If it is higher, ask whoever accepted the price before you resume: a run that stopped on cost_changed stopped so that a higher price is not charged without them. Then resume. The key also needs jobs:write, and the scopes of the stages that restart.
The answer is a new localization job with parent_job_id set to the failed one, because a job’s status never moves backwards. It lists the succeeded stages with their child jobs, and never runs or charges them again. Failed, skipped and unreached stages start at today’s price, in order, unless a current result is reused at no charge. A dub stage that restarts this way is a manual dub: its text_adaptation is as_written, and it is priced on speech seconds. A failed run can be resumed once. Otherwise resuming answers 409 job_not_resumable, and reason says why: In those cases, start a new run.

The whole program

run_localization.py