# How to Dub Videos with Python: A Developer's Guide

Step-by-step tutorial for dubbing videos programmatically with Python. Use the Pinch Dubbing API to translate video and audio files into 10 languages with a few lines of code.

## What you’ll build

By the end of this guide, you’ll have a Python script that takes a video file, dubs it into a target language, and downloads the result — all in about 30 lines of code. No machine learning setup, no GPU, no model downloads. Just HTTP requests to a REST API.

This is useful for:

- Batch processing video libraries
- Automating multilingual content pipelines
- Integrating dubbing into CI/CD or content management workflows
- Building tools that need localized video output

## Prerequisites

- Python 3.8+
- A Pinch API key ( [sign up free](https://portal.startpinch.com/dashboard/dubbing) — $5 credits included, no credit card)
- The `requests` library (`pip install requests`)

## The complete script

Here’s the full working example. We’ll break down each part below.

```
import requests
import time
import sys

API_BASE = "https://api.startpinch.com/api/dubbing"
API_KEY = "YOUR_API_KEY"  # Replace with your key

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

def dub_video(source_url: str, target_lang: str) -> str:
    """Submit a dubbing job and wait for the result."""

# 1. Submit the job
    resp = requests.post(
        f"{API_BASE}/jobs",
        headers=headers,
        json={"source_url": source_url, "target_lang": target_lang},
    )
    resp.raise_for_status()
    job = resp.json()
    job_id = job["id"]
    print(f"Job submitted: {job_id}")

# 2. Poll until complete
    while True:
        status_resp = requests.get(f"{API_BASE}/jobs/{job_id}", headers=headers)
        status_resp.raise_for_status()
        data = status_resp.json()

if data["status"] == "completed":
            print("Dubbing complete.")
            return data["result_url"]
        elif data["status"] == "failed":
            raise RuntimeError(f"Job failed: {data.get('error', 'unknown')}")

print(f"Status: {data['status']}... waiting")
        time.sleep(5)

def download(url: str, output_path: str):
    """Download the dubbed file."""
    resp = requests.get(url, stream=True)
    resp.raise_for_status()
    with open(output_path, "wb") as f:
        for chunk in resp.iter_content(chunk_size=8192):
            f.write(chunk)
    print(f"Saved to {output_path}")

if __name__ == "__main__":
    source = sys.argv[1] if len(sys.argv) > 1 else "https://example.com/video.mp4"
    lang = sys.argv[2] if len(sys.argv) > 2 else "es"

result_url = dub_video(source, lang)
    download(result_url, f"dubbed_{lang}.mp4")
```

## How it works

### Submitting a job

The `/jobs` endpoint accepts a JSON body with two required fields:

- `source_url` — A publicly accessible URL to your video or audio file. Supported formats: MP4, MOV, WebM, MP3, WAV, M4A.
- `target_lang` — An ISO 639-1 language code. Pinch currently supports: `es`, `fr`, `de`, `it`, `pt`, `ru`, `ja`, `ko`, `zh`, and `en`.

The API returns a job object with an `id` that you use to track progress.

### Polling for completion

Dubbing jobs are asynchronous. A 5-minute video typically takes 1–3 minutes to process. The script polls every 5 seconds until the status is `completed` or `failed`.

The response object includes:

- `status` — One of `processing`, `completed`, `failed`
- `result_url` — Available when status is `completed`. A signed URL valid for 48 hours.
- `error` — Available when status is `failed`. Describes what went wrong.

### Downloading the result

The `result_url` is a direct download link to the dubbed file. The output format matches the input — if you sent an MP4, you get an MP4 back with the original video and dubbed audio track.

## Batch processing multiple videos

For a library of videos, you can submit all jobs first, then poll them in parallel:

```
import concurrent.futures

videos = [
    ("https://cdn.example.com/lesson-1.mp4", "es"),
    ("https://cdn.example.com/lesson-2.mp4", "es"),
    ("https://cdn.example.com/lesson-3.mp4", "es"),
]

with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    futures = {
        executor.submit(dub_video, url, lang): (url, lang)
        for url, lang in videos
    }
    for future in concurrent.futures.as_completed(futures):
        url, lang = futures[future]
        try:
            result_url = future.result()
            filename = url.split("/")[-1].replace(".mp4", f"_{lang}.mp4")
            download(result_url, filename)
        except Exception as e:
            print(f"Failed: {url} -> {e}")
```

This processes all videos concurrently, significantly reducing total wall-clock time for large batches.

## Dubbing into multiple languages

To dub a single video into all supported languages:

```
LANGUAGES = ["es", "fr", "de", "it", "pt", "ru", "ja", "ko", "zh"]

source = "https://cdn.example.com/my-video.mp4"

for lang in LANGUAGES:
    result_url = dub_video(source, lang)
    download(result_url, f"my-video_{lang}.mp4")
```

At $0.50/min with Pinch, dubbing a 5-minute video into all 9 non-English languages costs $22.50 total.

## Error handling

Production code should handle common failure modes:

- **Network timeouts** — Add `timeout` to requests calls and implement retry logic
- **Rate limits** — The API returns 429 if you exceed rate limits. Back off exponentially.
- **Invalid URLs** — Ensure source URLs are publicly accessible. Private/authenticated URLs will fail.
- **Unsupported formats** — Check file format before submitting. The API returns a clear error for unsupported types.

## Next steps

- [Full API Reference](/content/docs/dubbing-api/index.html) — Complete endpoint documentation with all parameters and response schemas
- [Dubbing Quickstart](/content/docs/dubbing-quickstart/index.html) — Alternative walkthrough with curl examples
- [Try the browser UI](https://portal.startpinch.com/dashboard/dubbing) — Test dubbing quality before writing code
- [Supported languages](/content/docs/supported-languages/index.html) — Full list with language codes

## Try Pinch Dubbing free

Sign up and get $5 of free credits — enough for 10 minutes of dubbing. Upload a video in your browser or integrate via our API.
