# Pinch API — Full Documentation > Speech translation API. Real-time audio translation and async video dubbing. Base URL: https://api.startpinch.com Auth: Bearer token in Authorization header (`Authorization: Bearer `) API keys: https://portal.startpinch.com/dashboard/developers --- # Real-time Translation Stream audio in, get translated audio and transcripts back in real time. Supports 50+ languages with voice cloning. ## Create Translation Session POST /api/beta1/session ### Request Headers | Header | Value | Required | | --- | --- | --- | | Authorization | Bearer | Yes | | Content-Type | application/json | Yes | ### Request Body ```json { "sourceLanguage": "en-US", "targetLanguage": "es-ES", "voiceType": "clone" } ``` | Field | Type | Required | Description | | --- | --- | --- | --- | | sourceLanguage | string | Yes | Source language code hint (e.g. "en-US") | | targetLanguage | string | Yes | Target language code (e.g. "es-ES") | | voiceType | string | No | "clone", "female", or "male" (default: "clone") | ### Response (200) ```json { "url": "wss://pinch-prod-interpreter-jgw70la3.livekit.cloud", "token": "eyJhbGciOiJIUzI1NiJ9...", "room_name": "api-44a70196" } ``` | Field | Type | Description | | --- | --- | --- | | url | string | WebSocket URL for LiveKit connection | | token | string | JWT token for authenticating to room | | room_name | string | Unique room identifier (format: api-) | ### Error Responses - 400: `{"error": {"code": "invalid_language", "message": "Unsupported target language: xx-XX"}}` - 401: `{"error": {"code": "invalid_token", "message": "Invalid or expired API token"}}` - 429: `{"error": {"code": "rate_limit_exceeded", "message": "Too many requests"}}` - 500: `{"error": {"code": "internal_error", "message": "An internal error occurred"}}` ## Connecting to a Session After creating a session, connect using a LiveKit client SDK: ```javascript // JavaScript example const { url, token } = await fetch('https://api.startpinch.com/api/beta1/session', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ sourceLanguage: 'en-US', targetLanguage: 'es-ES', voiceType: 'clone' }) }).then(r => r.json()); const room = new Room(); await room.connect(url, token); await room.localParticipant.setMicrophoneEnabled(true); ``` ## Receiving Transcripts (Data Messages) Transcripts are published via LiveKit data channel (DataReceived event). ### Original Transcript ```json { "type": "original_transcript", "text": "All right, so I just have a bottle in front of me which is in red and pink in color.", "timestamp": 1770933625.791183, "is_final": true, "confidence": 0, "language_detected": "en-US" } ``` ### Translated Transcript ```json { "type": "translated_transcript", "text": "Muy bien, entonces tengo una botella delante de mi que es de color rojo y rosa", "timestamp": 1770933619.270732, "is_final": true, "confidence": 0, "language_detected": "en-US" } ``` - `is_final: false` = interim (partial, may change). Only for original_transcript. - `is_final: true` = final, stable. All translated_transcript messages are final. - `language_detected` = detected source language code. ## Receiving Translated Audio Translated audio arrives as a LiveKit audio track. Subscribe to TrackSubscribed events: ```javascript room.on(RoomEvent.TrackSubscribed, (track) => { if (track.kind !== Track.Kind.Audio) return; const audioEl = document.createElement("audio"); audioEl.autoplay = true; track.attach(audioEl); document.body.appendChild(audioEl); }); ``` ## Python SDK Install: `pip install pinch-sdk` Repo: https://github.com/pinch-eng/pinch-python-sdk ### File-based translation ```python import asyncio from pinch import PinchClient async def main(): client = PinchClient() # reads PINCH_API_KEY env var await client.translate_file( input_wav_path="input.wav", output_wav_path="output.wav", transcript_path="transcript.txt", source_language="en-US", target_language="es-ES", audio_output_enabled=True ) asyncio.run(main()) ``` Input: 16-bit PCM WAV, 16kHz or 48kHz. Install `pinch-sdk[audio]` for resampling support. ### Streaming translation ```python from pinch import PinchClient from pinch.session import SessionParams client = PinchClient() session = client.create_session(SessionParams(source_language="en-US", target_language="es-ES")) stream = await client.connect_stream(session, audio_output_enabled=True) # Send audio await stream.send_pcm16(pcm_bytes, sample_rate=16000, channels=1) # Receive events async for event in stream.events(): if event.type == "transcript": print(event.kind, event.is_final, event.text) elif event.type == "audio": pcm_bytes = event.pcm16_bytes sample_rate = event.sample_rate await stream.aclose() ``` --- # Video Dubbing API Async video dubbing. Submit a video URL, get a fully dubbed version in another language. - Pricing: $0.50 per minute of input video - Max duration: 10 minutes - Max file size: 500 MB - Rate limit: 10 jobs per minute - Output expiry: Download URLs expire after 48 hours - Supported languages: en, es, fr, de, it, pt, ru, ja, ko, zh ## Quick Example (curl) ```bash # 1. Create a dubbing job from a URL curl -X POST https://api.startpinch.com/api/dubbing/jobs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "source_url": "https://example.com/video.mp4", "source_lang": "auto", "target_lang": "es" }' # 2. Poll for completion curl https://api.startpinch.com/api/dubbing/jobs/JOB_ID \ -H "Authorization: Bearer YOUR_API_KEY" # 3. Download the result when status is "completed" curl https://api.startpinch.com/api/dubbing/jobs/JOB_ID/result \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Upload Video (optional) POST /api/dubbing/upload-url Use this if your video isn't publicly accessible. ### Request Body ```json { "filename": "video.mp4", "content_type": "video/mp4" } ``` | Field | Type | Required | Description | | --- | --- | --- | --- | | filename | string | Yes | Name of the video file | | content_type | string | Yes | MIME type (e.g. "video/mp4") | ### Response (200) ```json { "upload_url": "https://s3.amazonaws.com/pinch-dubbing/uploads/abc123?X-Amz-Algorithm=...", "source_url": "https://s3.amazonaws.com/pinch-dubbing/uploads/abc123", "upload_id": "abc123", "max_file_size_bytes": 500000000, "expires_in_sec": 3600 } ``` Upload the file with: `PUT ` with Content-Type header and binary body. Then use `source_url` when creating a dubbing job. ## Create Dubbing Job POST /api/dubbing/jobs ### Request Body ```json { "source_url": "https://s3.amazonaws.com/pinch-dubbing/uploads/abc123", "target_lang": "es", "source_lang": "auto" } ``` | Field | Type | Required | Description | | --- | --- | --- | --- | | source_url | string | Yes | URL of the video (public URL or from upload endpoint) | | target_lang | string | Yes | Target language code (en, es, fr, de, it, pt, ru, ja, ko, zh) | | source_lang | string | No | Source language code or "auto" (default: "auto") | ### Response (201) ```json { "job_id": "dub_7f3a1b2c", "status": "pending", "source_lang": "auto", "target_lang": "es", "created_at": "2026-03-05T14:30:00Z", "limits": { "max_duration_sec": 600, "max_file_size_bytes": 500000000 } } ``` ## Get Job Status GET /api/dubbing/jobs/{id} ### Response (200) ```json { "job_id": "dub_7f3a1b2c", "status": "completed", "source_lang": "auto", "target_lang": "es", "error": null, "progress": { "stage": "completed", "percent": 100 }, "input_duration_sec": 61.5, "cost_usd": 0.51, "output_url": "https://s3.amazonaws.com/pinch-dubbing/results/dub_7f3a1b2c.mp4?...", "output_expires_at": "2026-03-06T14:30:00Z", "created_at": "2026-03-05T14:30:00Z", "updated_at": "2026-03-05T14:35:22Z" } ``` | Field | Type | Description | | --- | --- | --- | | job_id | string | Unique job identifier | | status | string | pending, downloading, processing, uploading, completed, failed | | error | string/null | Error message if failed | | progress | object | { stage, stage_name, percent } | | input_duration_sec | number | Input video duration | | cost_usd | number | Cost in USD | | output_url | string/null | Presigned download URL (when completed) | | output_expires_at | string/null | Download URL expiry (ISO 8601) | ### Status Flow pending → downloading → processing → uploading → completed Any status can transition to → failed ## Get Download URL (refresh) GET /api/dubbing/jobs/{id}/result Use if the original output_url has expired. ### Response (200) ```json { "job_id": "dub_7f3a1b2c", "download_url": "https://s3.amazonaws.com/pinch-dubbing/results/dub_7f3a1b2c.mp4?...", "expires_at": "2026-03-06T14:30:00Z" } ``` ## List Jobs GET /api/dubbing/jobs?limit=20&offset=0 | Parameter | Type | Default | Description | | --- | --- | --- | --- | | limit | number | 20 | Max 100 | | offset | number | 0 | Pagination offset | ### Response (200) ```json { "jobs": [ { "job_id": "dub_7f3a1b2c", "status": "completed", "source_lang": "en", "target_lang": "es", "created_at": "...", "updated_at": "..." } ], "total": 5, "limit": 20, "offset": 0 } ``` ## Error Codes ### HTTP Errors - 400 invalid_url: Source URL is not valid - 400 unsupported_language: Target language not supported - 401 unauthorized: Invalid or expired API token - 402 insufficient_balance: Account balance too low - 429 rate_limited: Max 10 requests per minute ### Job-Level Errors (in status response) - video_too_long: Exceeds 10 min limit - video_too_large: Exceeds 500 MB limit - unsupported_format: Video format not supported - download_failed: Could not download source video - processing_failed: Internal error during dubbing --- # Supported Languages ## Real-time Translation (50+ languages) Source and target language codes use regional variants (e.g. en-US, es-ES, fr-FR). Full list at: https://www.startpinch.com/docs/supported-languages Common codes: en-US, en-GB, es-ES, es-US, fr-FR, de-DE, it-IT, pt-BR, pt-PT, ru-RU, ja-JP, ko-KR, zh-CN, zh-TW, ar-SA, hi-IN, nl-NL, sv-SE, da-DK, fi-FI, nb-NO, pl-PL, tr-TR, uk-UA, vi-VN, th-TH, id-ID, ms-MY, cs-CZ, el-GR, he-IL, hu-HU, ro-RO, sk-SK, bg-BG, hr-HR, lt-LT, lv-LV, sl-SI, et-EE, ca-ES, gl-ES, eu-ES, af-ZA, sw-KE, fil-PH, bn-IN, ta-IN, te-IN, mr-IN, gu-IN, kn-IN, ml-IN ## Video Dubbing (10 languages) en, es, fr, de, it, pt, ru, ja, ko, zh --- # Links - Documentation: https://www.startpinch.com/docs - Developer Portal: https://portal.startpinch.com/dashboard/developers - Dubbing Dashboard: https://portal.startpinch.com/dashboard/dubbing - Python SDK: https://github.com/pinch-eng/pinch-python-sdk - Node.js demo: https://github.com/pinch-eng/pinch-realtime-demo - Support: support@startpinch.com