---
title: "Dubbing a finished order"
url: https://lumean.app/en/developers/docs/guide/dubbing
locale: en
description: "How to translate a finished Cartesia or ElevenLabs voiceover into another language. The options reference, the price before ordering, creating a dub, and common refusals."
updated: 2026-11-06
sources: [get-orders-dubbing-options, get-orders-order-dub-quote, post-orders-order-dub, get-orders-order, post-storage-url]
errors: ["402", "404", "409", "422", "429", service-not-found, token-quota-exceeded]
spec_version: 1.0.0
---

# Dubbing a finished order

Dubbing translates a finished voiceover into another language and voices the translation. Every
phrase of the dub starts where the source phrase starts, and the track has the same length. You
don't send any text: the service does the translation. The result is a new order; the source
order stays as it is.

| Source (`service_key` of the order) | Dub `task_type` | Price per source character |
| --- | --- | --- |
| `cartesia` | `cartesia_dub` | 1.35 Cartesia characters, translation included |
| `elevenlabs` | `elevenlabs_dub` | 1.5 ElevenLabs characters, translation included |

Take the languages, models, length cap, price factor and maintenance flag only from
`GET /orders/dubbing/options`. The table above is a guide; don't hard-code it.

## Options: is dubbing available

`GET /orders/dubbing/options` tells which dubbing kinds are open to the key owner. Pick the kind
by the source order's `service_key`: `data.kinds[order.service_key]`.

| Kind field | Meaning |
| --- | --- |
| `available` | whether the kind is open to this account |
| `dub_service` | `task_type` of the future order: `cartesia_dub` or `elevenlabs_dub` |
| `languages`, `models`, `default_model` | allowed dub languages and models |
| `max_source_chars` | source length cap in characters |
| `price_factor` | price multiplier applied to the source characters |
| `maintenance` | `true` means intake is paused for now, and creation returns `503` |

A closed kind comes with `available: false`, `dub_service: null`, empty lists and zeros. That is
a "feature not available" answer, not an error. The top-level `data` fields (except `kinds`)
repeat the `cartesia` kind for older clients.

### GET /orders/dubbing/options

Dubbing options

Справочник: https://lumean.app/en/developers/docs/api/get-orders-dubbing-options

## Which order can be dubbed

- your own `cartesia` or `elevenlabs` voiceover order with status `completed` or
  `result_delivered`;
- the order's files are still stored (see [Files and storage](/developers/docs/guide/files));
- the order is not in paragraph mode (`generation_mode: "paragraph"`): one track is required;
- no regeneration or stitching is running on the order;
- the source is no longer than `max_source_chars`.

Otherwise creation and the quote return `422` with a `reason` from the refusals table below.

The dub language must differ from the source language. For Cartesia the source language is known
from the template, and a match is refused right away with `422` `dub_same_language`. For
ElevenLabs the source language is unknown (`source_language: "auto"`): such a dub is created,
fails at the worker and refunds in full. Watch the language yourself.

## Price before ordering

`GET /orders/{order}/dub/quote` prices the dub and charges nothing; it doesn't spend the key's
token quota either. The limit is 60 requests per minute per key. The query takes the same fields
as the creation body, all optional: the price depends only on the source characters.

| `data` field | Meaning |
| --- | --- |
| `source_chars` | source characters: the paid length of the latest versions of its fragments |
| `tokens` | `tokens_from_quota` + `tokens_from_payg` |
| `lmc_cost_minor` | PAYG top-up from the balance, minor LMC |
| `price_lumc_minor` | the full price, even when the quota covers everything |
| `allowed`, `reason` | whether creation would pass now; `reason` is the same code creation would return |
| `defaults` | the `voice_id` and `model_id` the dub will use |
| `templates` | your templates of the same service, up to 100: candidates for `template_id` |

Amounts are in minor units: `real = value / 10^currency_asset.precision`.
`defaults.voice_id: null` means the default voice is no longer available (removed from the
catalog, clone deleted): pass `voice_id` when creating.

### GET /orders/{order}/dub/quote

Dub quote

Справочник: https://lumean.app/en/developers/docs/api/get-orders-order-dub-quote

## Creating a dub

`POST /orders/{order}/dub` creates the dub order. The body is JSON:

| Field | Rule | Meaning |
| --- | --- | --- |
| `target_language` | required, from the kind's `languages` | dub language, different from the source language |
| `voice_id` | optional, string ≤ 64 | dub voice. Cartesia: a catalog voice UUID or your clone's `voice_id`; ElevenLabs: a 20-character voice id |
| `model_id` | optional, from the kind's `models` | model. Without it, the template's model, otherwise `default_model` |
| `template_id` | optional | your template of the same service as the source: its voice, model and settings are used |
| `name` | optional, string ≤ 120 | order name. Without it, "Source name → EN" |

The default voice and model come from the snapshot of the source order's template, as the
template was when the source was created. Explicit `voice_id` and `model_id` override the
template.

The response is `201` with the new order in `data`: `task_type` is `cartesia_dub` or
`elevenlabs_dub`, with one fragment. From here it is a regular order: the status arrives over
[WebSocket](/developers/docs/guide/realtime) or by polling `GET /orders/{order}`, the track is in
`result.files[]`, subtitles are in `result.service_files[]`, and `POST /storage/url` returns the
link.

### POST /orders/{order}/dub

Dub an order

Справочник: https://lumean.app/en/developers/docs/api/post-orders-order-dub

```bash
BASE=https://api.lumean.app/api/public
SRC=<ORDER_UUID>   # a finished voiceover order

curl -s "$BASE/orders/dubbing/options" -H "X-API-KEY: $KEY"
curl -s "$BASE/orders/$SRC/dub/quote?target_language=en" -H "X-API-KEY: $KEY"
curl -s -X POST "$BASE/orders/$SRC/dub" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
  -d '{ "target_language": "en" }'
# → 201, data.id = <DUB_UUID>, data.task_type = "cartesia_dub"
```

The key needs `orders.read` (options and quote), `orders.write` (creation) and `orders.download`
(the file link).

## Payment

Payment works like a regular voiceover. The subscription quota is spent first, by the source
service's entitlement: a subscription with Cartesia also pays for a Cartesia dub. The rest is
charged to the balance as PAYG. The cost also counts against the
[key's token quota](/developers/docs/guide/limits): when it is exceeded, the order is not created
and the response is `429` `token_quota_exceeded`. A failed dub refunds in full.

A dub can be cancelled before work starts (`POST /orders/{order}/cancel`). It doesn't need
`retry`: on failure the money comes back, so create the dub again.

## Refusals

| `reason` | HTTP | Meaning |
| --- | --- | --- |
| `dub_source_unavailable` | 422 | the source can't be dubbed: not a finished `cartesia`/`elevenlabs` voiceover, files expired, no phrase timings, paragraph mode, regeneration or stitching in progress |
| `dub_source_too_long` | 422 | the source is longer than the cap; the body also has `source_chars` and `max_source_chars` |
| `dub_same_language` | 422 | the dub language matches the source language (Cartesia only) |
| `service_not_found` | 422 | this dubbing kind is not available to your account |
| `duplicate_order` | 409 | the same request (source and fields) less than a minute ago. For a second dub into the same language, change `name` |

A field error (`target_language` not in the list, someone else's or a deleted `template_id`) is
`422` with the field in `errors`, and nothing is charged. Someone else's or a missing order is
`404`, not enough money for the PAYG top-up is `402`, and maintenance of the kind is `503`.

### 422 · `service_not_found` — service_not_found — service not found

| Что произошло | Что делать |
| --- | --- |
| The order was not created. The response is a 422 with `reason: "service_not_found"` and no `errors`. The request passed field validation, but no service was found for it. | Send only the types that an API key can create. |

`Retry-After`: нет. Разбор: https://lumean.app/en/developers/docs/errors/service-not-found

---

- This page in the browser: https://lumean.app/en/developers/docs/guide/dubbing
- Full machine-readable reference: https://api.lumean.app/docs/llm.md
