> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reedapt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Dubs

> Start dubs from an upload, follow their progress, and download the results.

## Starting dubs

`POST /dubs` turns a completed upload into one dub per language:

```bash theme={null}
curl https://api.reedapt.com/v1/dubs \
  -H "Authorization: Bearer $REEDAPT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042" \
  -d '{
        "upload_id": "job_3f9a2c7e1b4d",
        "source_language": "en",
        "target_languages": ["fr", "es"],
        "metadata": {"order_id": "1042"}
      }'
```

| Field | Notes |
| - | - |
| `upload_id` | An upload whose status is `uploaded`. |
| `source_language` | The language spoken in the file, such as `en`. |
| `target_languages` | One dub is made for each. `GET /languages` lists the codes your plan covers. More than one language needs a plan with bulk dubbing. |
| `voice_cloning` | Defaults to `true`: each speaker keeps their own voice. |
| `num_speakers` | How many people speak, if you know. Left out, we work it out. |
| `metadata` | Your own keys and values, up to 2 KB, returned on the dub and in its webhooks. |

The answer lists the dubs that started. Languages that couldn't start come back in `refused` with a reason, and the others still start:

```json Response theme={null}
{
  "dubs": [
    { "id": "job_3f9a2c7e1b4d", "object": "dub", "status": "queued", "target_language": "fr", "…": "…" }
  ],
  "refused": [
    { "target_language": "es", "code": "LANGUAGE_NOT_IN_PLAN", "message": "Your plan doesn't include this language." }
  ]
}
```

## Minutes

Dubs are counted in minutes of source media, once per language. Each dub reserves its minutes when it starts. If a dub fails or you cancel it, its minutes are returned. Check what's left with `GET /usage`. Test keys use no minutes.

## Dubs running at once

Your plan sets how many dubs can be unfinished at the same time: 3 on Creator, 10 on Professional studio and 25 on Ministry & Platform. Past that, new dubs get `429 TOO_MANY_DUBS_RUNNING` until some finish. The limit is per account, across all its keys and the Reedapt app.

## Following a dub

A dub moves through these statuses. `completed` and `failed` are final.

```mermaid theme={null}
flowchart LR
  queued --> processing --> completed
  processing --> failed
  queued --> failed
```

While a dub is `processing`, `progress` runs from 0 to 100 and `stage` says what it's doing. Show `stage` if you like, but don't build logic on its values: they may change as we improve the pipeline.

> [!TIP]
>
> Use [webhooks](https://docs.reedapt.com/guides/webhooks.md) rather than polling. If you poll `GET /dubs/{id}`, once every 30 seconds is plenty.

```json A completed dub theme={null}
{
  "id": "job_3f9a2c7e1b4d",
  "object": "dub",
  "status": "completed",
  "stage": null,
  "progress": 100,
  "source_language": "en",
  "target_language": "fr",
  "audio": false,
  "test": false,
  "preview_seconds": null,
  "duration_minutes": 12.4,
  "created_at": "2026-10-28T09:12:44",
  "started_at": "2026-10-28T09:12:51",
  "completed_at": "2026-10-28T09:31:02",
  "error": null,
  "metadata": { "order_id": "1042" }
}
```

A failed dub has an `error` with a `code` and a `message` you can show to people. See [Errors](https://docs.reedapt.com/errors.md#why-a-dub-failed) for the codes.

## Downloading the files

`GET /dubs/{id}/files` returns links to a completed dub's files. Each link lasts an hour; ask again for fresh ones.

| Kind | What it is |
| - | - |
| `dub` | The dubbed video, or the dubbed audio as MP3 for an audio file. |
| `dubbed_audio_wav` | Audio dubs only: the dub as WAV. |
| `voice` | Audio dubs only: the dubbed voices on their own. |
| `background` | Audio dubs only: the music and sound without the voices. |

Test dubs return only `dub`, the watermarked preview.

> [!NOTE]
>
> Dubs and their files are kept for a limited time, as in the Reedapt app. Download what you need to keep. A dub whose files are gone answers `404 FILES_GONE`.

## Listing and cancelling

* `GET /dubs` lists the account's dubs, newest first. Page with `limit` (up to 100) and `offset`; `has_more` says whether another page follows.
* `POST /dubs/{id}/cancel` stops a dub that hasn't finished and deletes it. Its minutes are returned.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.