Workflows

    Running a dub queue and polling status

    Multi-language dubbing is an ops job. Build a manifest, name every submission, poll each project, and reconcile before anything publishes.

    Versely Team9 min read

    The dub that fails loudly is not the problem. The problem is the one that fails while nine others succeed, in a batch nobody wrote down, dispatched by someone who is now in a different meeting. Two days later a market goes live with the English audio track still attached, and reconstructing which of the ten languages actually completed takes longer than the dubbing did.

    Multi-language dubbing is asynchronous by design. The job is submitted, an ID comes back, and the result arrives whenever it arrives. That is the correct architecture and it means the work is not "run a dub" — it is running a queue, which is an operations problem with an operations solution: a manifest, a naming convention, a poll loop, and a reconcile gate before anything ships.

    Step 0: freeze the master, and host it

    Two preconditions, both of which fail late and expensively if skipped.

    The source has to already live on Versely. A dub takes media that is a prior generation, an upload, or the output of another job. An external link — a YouTube URL, a client's Drive share — is not a valid source. Downloading and re-uploading outside footage is step zero of the workflow, not a thing you discover mid-batch.

    The master edit has to be approved before fan-out. Every dub derives from it, and a resubmission is a new job rather than a correction of the old one. A copy change caught after ten languages are in flight is not a fix; it is ten more jobs. Get sign-off on the master, then dispatch, in that order and never the other one.

    While you are freezing it, export the master without burned-in captions. Captions live in the pixels, so English subtitles on the master become English subtitles on all ten dubs, permanently.

    Build the manifest before you dispatch

    One row per language, filled in before the first submission and updated as results land. A spreadsheet is fine. What matters is that it exists before the queue does, because a manifest built after the fact is just a guess.

    Language Dub target? Engine Job name Project ID Status Captioned
    Spanish yes ElevenLabs prodlaunch-v3-es
    German yes ElevenLabs prodlaunch-v3-de
    Japanese yes HeyGen prodlaunch-v3-ja

    Three of those columns do work before you submit anything.

    Dub target. Not every supported speech language is a dubbing target. The current table lists 38 languages for speech and 25 of them as dub targets. Czech, Danish, Finnish, Greek, Hebrew, Hungarian, Malay, Norwegian, Persian, Filipino, Bulgarian, Croatian and Slovak sit in the speech set without being dub targets. A language list assembled from a marketing plan rather than from the capability map will contain at least one of these, and finding out at dispatch time is better than finding out at launch time.

    Engine. ElevenLabs is the default and handles audio or video, up to 30 minutes, with trimming inside the same submission. HeyGen is video-only, caps at 8 minutes, does not support trimming, and supports a narrower set of languages. The full decision sequence is in two dubbing engines and their hard limits — for queue purposes, what matters is that the engine is decided per row before dispatch, not argued about mid-batch.

    Job name. This is the column that makes the whole thing work.

    Name every submission or lose the queue

    The dub tool takes a name on submission. Skipping it is the single most common reason a batch becomes unreadable.

    Your dub listing returns projects newest first. If ten of them were submitted in the same four minutes with default names, the listing tells you that ten dubs exist and nothing about which is which. If they were submitted as prodlaunch-v3-es, prodlaunch-v3-de and so on, the listing is the status board.

    A convention that survives contact with a second batch:

    <project>-<master-version>-<language-code>
    

    The master version matters more than it looks. When the master gets re-cut and the batch reruns, prodlaunch-v4-es sitting next to prodlaunch-v3-es is immediately legible, and the stale one is obvious. Without a version segment, a rerun produces two projects with identical names and no way to tell which output is current except by timestamp — which is exactly the reasoning that puts the wrong file in front of a client.

    Capture the returned project ID into the manifest as each submission goes out. The listing is a recovery path for when you lost the ID; it is not a substitute for writing it down.

    Poll, do not wait

    Two calls do the work.

    Status by ID takes one project ID and returns its state — queued, dubbing, completed or failed — plus the output URL once it is done. This is the call for a specific row.

    The project listing returns your dubs newest first with a limit and a pagination cursor. This is the call for a sweep across the whole batch, and the reason the naming convention earns its keep.

    The states map cleanly onto what to do:

    State Meaning Action
    queued Accepted, not started Nothing. Poll again later.
    dubbing In progress Nothing. Poll again later.
    completed Output available Record the output URL in the manifest. Row is not done yet.
    failed Terminal Diagnose before resubmitting. A blind retry repeats the failure and costs another job.

    The discipline in an agent-driven workflow is to submit and move on rather than sitting on a turn waiting for a result that arrives minutes later. Dispatch the whole language list, then come back and sweep. "Is my dub done" is a follow-up question, not something to block on.

    Poll on a cadence that matches the runtime rather than every few seconds. A 12-minute source is not going to finish in 30 seconds and hammering the status endpoint tells you nothing a slower loop would not.

    The partial-failure playbook

    A batch of ten will not always come back ten-for-ten, and the recovery is different depending on what failed.

    • One language failed, the rest completed. Do not rerun the batch. Rerunning nine successful languages costs nine additional jobs and produces nine identical outputs, because there is no batch discount and a resubmission is billed as a new job. Fix the one row.
    • The failure is engine-shaped. If a HeyGen row failed and the source is over 8 minutes, or the target language sits outside HeyGen's set, the fix is the engine, not a retry. Change the engine on that row and resubmit once.
    • Every row failed. The problem is upstream of the queue. Check the source: hosted on Versely, actually reachable, actually containing speech. A batch that fails uniformly usually failed at step 0.
    • A row completed but the output is wrong. Wrong here usually means the settings, not the model. Background audio stripped when it should have been kept, or a translation that overruns because dynamic duration was left off, or the wrong speaker count on a multi-speaker source. Fix the setting and resubmit that row.

    Log the failure reason in the manifest next to the row. The second time this batch runs — and it will run again when the master changes — that column is the difference between a clean rerun and rediscovering the same problem.

    The reconcile gate

    Nothing publishes until the manifest is complete. That is the entire gate and it is worth being rigid about, because the failure this prevents is invisible at the individual-job level and obvious to an audience.

    Three checks per row before it is marked shippable:

    1. Status is completed and an output URL is recorded. Not "it was running last time I looked."
    2. The output has been opened. A completed job with a file nobody played is an assumption.
    3. The caption job for that language has run. Dubbing translates spoken audio; it does not translate captions or on-screen text. Captioning is a separate job per language, and it transcribes from the dubbed output rather than from the English master. A row without a caption job is not finished, it just looks finished.

    Then publish the set together. Publishing markets as they complete is tempting and it converts a queue into a set of independent launches with no shared review, which is where the English-audio-in-a-German-market failure actually comes from.

    For the shape of the bill across a batch, dubbing a video into 10 languages walks through why the language count is the only real multiplier and which variables do not move the number at all. The dub video task and the dubbing tool page are the direct surfaces, what dubbing is is the concept page, and the agent capability for dubbing is the conversational route into the same job.

    FAQ

    Should I dispatch all languages at once or run them in waves?

    All at once, once the master is frozen. The jobs are independent — a failure in one does not block the others — so serializing them only adds wall-clock time. Waves make sense for a different reason: if you are unsure about a setting, dub one language first, check the output, then fan out the remaining nine with the confirmed settings.

    What happens if I resubmit a language that already completed?

    You get a second job, billed as a job, with its own project ID and its own output. Nothing is deduplicated. That is why the manifest matters more than it seems — the cost of losing track is not confusion, it is duplicate work you paid for.

    Can I poll the listing instead of tracking individual project IDs?

    For a small batch with disciplined names, yes, and it is the faster sweep. For anything long-running or interleaved with other projects, track the IDs. The listing is newest-first and paginated, so a batch submitted before someone else's work drifts down the list and the sweep stops being a single call.

    Does the number of speakers or the target language change what a dub costs?

    No. A dub is billed as one flat job per submission, the same whichever target language you pick, and the speaker-count setting is a quality hint rather than a pricing dimension. The number of target languages is the multiplier, and the app quotes the batch before it runs.