DittoDub developer guides

Set up authentication, create projects, handle errors, and paginate list results.

Use DittoDub with an AI coding agent

Copy these Markdown instructions into Codex, Claude, or another coding agent. They cover authentication, project creation, polling, errors, and spending rules. Your API key is not included.

# DittoDub API setup

Human documentation: https://dittodub.com/docs/api
Base URL: https://api.dittodub.com

## Authentication
- Read the key from the DITTODUB_API_KEY environment variable.
- Send it as: x-api-key: $DITTODUB_API_KEY
- Never print, paste into source code, commit, or return the key in a response.

## Dubbing workflow
1. GET /v1/dubbing/locales and use the exact locale identifiers returned.
2. GET /v1/dubbing/projects or GET /v1/dubbing/youtube/videos to find existing work before creating a duplicate.
3. GET /v1/usage before billable work.
4. POST /v1/dubbing/projects with a unique Idempotency-Key.
5. For YouTube, set source to { "type": "youtube", "url": "https://..." }.
6. For a local video, create an upload source. PUT each part to its presigned URL, then POST the collected part numbers and ETags to the complete URL.
7. Read progress in GET /v1/dubbing/projects/{project_id}. Poll only when progress.poll_after_seconds is a number. When it is null, stop and report who has the next step.
8. When a language is completed, use the download_url returned with each deliverable.
9. To add languages, POST /v1/dubbing/projects/{project_id}/languages with preview_only true. Show the exact quote to the user. After confirmation, repeat with preview_only false and an Idempotency-Key.
10. To request human review, POST /v1/dubbing/projects/{project_id}/transcript-review with preview_only true. This reviews only the English source transcript. Show the exact quote, then repeat with preview_only false and an Idempotency-Key after confirmation.

## Rules
- max_billable_seconds is a hard safety ceiling, not an estimate. If validated media exceeds it, the project fails before processing or charging.
- The language-add ceiling applies to the entire operation. Previewing never charges or changes a project.
- Source transcript review is available only while an English transcript is awaiting validation. It never requests review for target-language transcripts.
- Create requests are idempotent. Reuse the same Idempotency-Key only for the same request body.
- List endpoints use cursor pagination. Pass page.next_cursor as cursor until page.has_more is false.
- Errors use application/problem+json and include type, title, status, code, and request_id.
- Overall status can be awaiting_upload, validating, queued, processing, awaiting_creator_review, in_human_review, completed, partial, or failed.
- A language waiting_for_transcript_review has not been queued for dubbing. Other language states are queued, processing, completed, or failed.

## Endpoints
- GET /v1/dubbing/locales: exact supported locales; no authentication required
- GET /v1/dubbing/youtube/videos: search connected channels and identify matching projects
- GET /v1/usage: total, reserved, and available workspace credits
- POST /v1/dubbing/projects: create a YouTube or upload project
- GET /v1/dubbing/projects: list and filter projects
- GET /v1/dubbing/projects/{project_id}: status, usage, transfer, and completed files
- POST /v1/dubbing/projects/{project_id}/languages: preview or add target languages
- POST /v1/dubbing/projects/{project_id}/transcript-review: preview or submit the English source transcript to Ditto Verified
- GET /v1/dubbing/projects/{project_id}/download: stable authenticated file download
- POST /v1/dubbing/projects/{project_id}/upload/complete: finalize multipart upload

## Minimal YouTube request
curl "https://api.dittodub.com/v1/dubbing/projects" \
  --request POST \
  --header "x-api-key: $DITTODUB_API_KEY" \
  --header "Idempotency-Key: YOUR_UNIQUE_OPERATION_ID" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "Launch video",
    "external_id": "YOUR_INTERNAL_ID",
    "source_locale": "en_us",
    "target_locales": ["es_mx"],
    "max_billable_seconds": 1800,
    "source": { "type": "youtube", "url": "YOUTUBE_URL" }
  }'

Before a POST that can spend credits, confirm the source, target locales, exact quote when available, and max_billable_seconds.

Authentication

A backend uses a service key. An integration acting for a signed-in person uses an OAuth access token.
Service key
x-api-key: $DITTODUB_API_KEY
OAuth access token
Authorization: Bearer $DITTODUB_ACCESS_TOKEN
Do not expose a service key in browser code, logs, prompts, or source control. Production requests should come from your server.

Project lifecycle

Each response says what is happening, who has the next step, and when to check again. Creator review and Ditto Verified review happen before target-language dubbing begins.

Follow the source transcript into each target language.

The project response shows who has the next step and when target-language dubbing begins.

1

Create

Start from YouTube or an uploaded source.

2

Transcribe

Prepare the source transcript.

3

Review or continue

Choose creator review, automatic dubbing, or Ditto Verified.

4

Dub and deliver

Process each target language and download completed files.

Errors

Error responses use application/problem+json. Read the stable code in your application. Save the request_id with your logs so support can find the request.
Example problem
{
  "type": "https://api.dittodub.com/problems/unsupported-locale",
  "title": "Invalid request",
  "status": 400,
  "detail": "target_locales contains unsupported locale 'es-us'.",
  "code": "unsupported_locale",
  "request_id": "req_01K2..."
}

Pagination

List projects returns up to 50 items. When page.has_more is true, pass page.next_cursor as the next request's cursor. Do not modify or reuse a cursor with different filters.