# How Tasks & Runs Work
Source: https://docs.camb.ai/api-reference/basics/tasks-and-runs
Understand the asynchronous task pattern used across CAMB.AI APIs
Most CAMB.AI APIs use an **asynchronous task pattern** that allows your application to submit requests and continue working while processing happens in the background. This guide explains how tasks and runs work.
## The Task Lifecycle
Send your data (text, audio, video) to a creation endpoint. The API immediately returns a `task_id`.
Use the `task_id` to check progress. The task moves through states: `PENDING` → `SUCCESS` (or `ERROR`).
Once the status is `SUCCESS`, you receive a `run_id`. Use this to download your result.
```mermaid theme={null}
sequenceDiagram
participant App as Your App
participant API as CAMB.AI API
App->>API: POST /tts (submit text)
API-->>App: { task_id: "abc123" }
loop Until SUCCESS
App->>API: GET /tts/{task_id}
API-->>App: { status: "PENDING" }
end
App->>API: GET /tts/{task_id}
API-->>App: { status: "SUCCESS", run_id: "xyz789" }
App->>API: GET /tts-result/{run_id}
API-->>App: [audio data]
```
## Task vs Run
| Concept | Description | ID |
| -------- | ------------------------------ | --------- |
| **Task** | A job submitted for processing | `task_id` |
| **Run** | The completed result of a task | `run_id` |
A task represents your request being processed. Once complete, the result becomes a run that you can download or reference.
## Task Status Types
| Status | Meaning | Action |
| ------------------ | ------------------------------ | ------------------------------ |
| `PENDING` | Processing in progress | Continue polling |
| `SUCCESS` | Completed successfully | Retrieve result using `run_id` |
| `ERROR` | Processing failed | Check error message, retry |
| `TIMEOUT` | Processing exceeded time limit | Break into smaller requests |
| `PAYMENT_REQUIRED` | Insufficient credits | Add credits to account |
## Example: Complete Workflow
Here's a complete example showing the task pattern for text-to-speech:
```python theme={null}
import requests
import time
API_KEY = "your-api-key"
BASE_URL = "https://client.camb.ai/apis"
headers = {
"x-api-key": API_KEY,
"Content-Type": "application/json"
}
# Step 1: Submit the task
response = requests.post(
f"{BASE_URL}/tts",
headers=headers,
json={
"text": "Hello, this is a test of the task system.",
"voice_id": 147320,
"language": "en-us" # Locale tag. Numeric IDs (e.g. 1) still work but are deprecated.
}
)
task_id = response.json()["task_id"]
print(f"Task submitted: {task_id}")
# Step 2: Poll for completion
while True:
status_response = requests.get(
f"{BASE_URL}/tts/{task_id}",
headers=headers
)
status_data = status_response.json()
status = status_data["status"]
print(f"Status: {status}")
if status == "SUCCESS":
run_id = status_data["run_id"]
break
elif status in ["ERROR", "TIMEOUT", "PAYMENT_REQUIRED"]:
print(f"Task failed: {status}")
exit(1)
time.sleep(2) # Wait before polling again
# Step 3: Download the result
result_response = requests.get(
f"{BASE_URL}/tts-result/{run_id}",
headers=headers,
stream=True
)
with open("output.wav", "wb") as f:
for chunk in result_response.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
print(f"Audio saved! Run ID: {run_id}")
```
## Polling Best Practices
Start with 2-5 second intervals. Shorter tasks (TTS) complete faster than longer ones (dubbing).
For longer tasks, increase the polling interval over time to reduce API calls.
Don't poll forever. Set a maximum wait time and handle timeouts gracefully.
Always handle `ERROR`, `TIMEOUT`, and `PAYMENT_REQUIRED` statuses in your code.
## Bulk Operations
For processing multiple items, use the bulk fetch endpoints:
```python theme={null}
# Fetch multiple results at once
response = requests.post(
f"{BASE_URL}/fetch-tts-results",
headers=headers,
json={
"run_ids": [123, 456, 789]
}
)
results = response.json()
```
## APIs Using This Pattern
Most CAMB.AI APIs follow the task pattern:
| API | Create | Status | Result |
| -------------- | -------------------------- | ----------------------------------- | ------------------------------------ |
| Text-to-Speech | `POST /tts` | `GET /tts/{task_id}` | `GET /tts-result/{run_id}` |
| Translation | `POST /translation` | `GET /translation/{task_id}` | `GET /translation-result/{run_id}` |
| Transcription | `POST /transcription` | `GET /transcription/{task_id}` | `GET /transcription-result/{run_id}` |
| Subtitles | `POST /sub` | `GET /sub/{task_id}` | `GET /sub-result/{run_id}` |
| Dubbing | `POST /end-to-end-dubbing` | `GET /end-to-end-dubbing/{task_id}` | `GET /dubbed-run-info/{run_id}` |
| Stories | `POST /create-story` | `GET /story/{task_id}` | `GET /story-run/{run_id}` |
## Streaming Alternative
For real-time applications, some APIs offer streaming endpoints that return data immediately without the task pattern:
* `POST /tts-stream` - Streaming text-to-speech
* `POST /translation/stream` - Deprecated streaming translation. Use `POST /translation` for new integrations.
Use streaming when you need immediate response and can process audio chunks as they arrive.
## Next Steps
SDKs handle polling automatically
Explore all endpoints
# Add Term to Dictionary
Source: https://docs.camb.ai/api-reference/endpoint/add-term-to-dictionary
post /dictionaries/{dictionary_id}/add-term
Adds a new term and its translations to an existing dictionary, enabling you to expand your multilingual terminology database with precise linguistic mappings.
This endpoint serves as your gateway to enriching dictionaries with new linguistic content. When you need to expand a dictionary's vocabulary, whether you're building a comprehensive translation resource or maintaining specialized terminology for your domain, this endpoint provides the mechanism to seamlessly add term-translation pairs that enhance your multilingual capabilities.
Think of this process as carefully placing a new entry into a physical dictionary, but with the added power of digital precision and immediate availability across all your applications. Each term you add becomes instantly searchable and usable through other dictionary endpoints, creating a growing repository of linguistic knowledge that serves your users' translation and terminology needs.
## The Update-Centric Approach
Notice that the operation summary describes this as "Update Term Translation In Dictionary Using Term ID" rather than simply "Add Term." This distinction reveals important architectural decisions about how the system handles dictionary content. Rather than treating each operation as creating entirely new database records, the system views term additions as updates to existing term structures.
This approach offers several advantages for dictionary management. It allows for versioning of translations, supports scenarios where terms need refinement over time, and provides mechanisms for tracking the evolution of linguistic content. When you "add" a term, you might actually be adding a new translation variant to an existing term concept, or updating existing translations with improved accuracy.
## Quality Considerations for Translation Content
Adding terms to dictionaries involves inherent quality considerations that go beyond technical correctness. Translation accuracy, cultural appropriateness, and consistency with existing dictionary content all influence the long-term value of your linguistic resources.
When designing term addition workflows, consider implementing validation steps that help ensure translation quality. This might involve requiring multiple translation variants, providing fields for usage examples or context information, or implementing review processes where translation additions require approval before becoming available to end users.
# Create Audio Separation
Source: https://docs.camb.ai/api-reference/endpoint/create-audio-separation
post /audio-separation
Creates a task to separate an audio file into distinct background and foreground components
Transform your mixed content into clean, isolated components with our powerful audio separation system. This innovative endpoint enables you to extract distinct foreground elements (such as vocals or lead instruments) from background elements (like accompaniment or ambient sounds). Whether you're producing music, cleaning up recordings, creating remixes, or developing audio-focused applications, this capability allows you to deconstruct complex media files into their fundamental components for enhanced control and creative flexibility.
For optimal separation quality, we recommend using media files with minimal compression and clear distinction between foreground and background elements. Higher quality input files generally produce better separation results.
## The Audio Separation Process
When you submit an audio separation request, our system begins a sophisticated workflow:
The system registers your request and establishes a dedicated processing task, returning a unique task identifier (`task_id`) that you'll use to track and retrieve your separated audio components.
Our advanced audio processing algorithms analyze the spectral and temporal characteristics of your audio file, identifying patterns that distinguish foreground from background elements.
Using specialized neural networks, the system carefully separates the audio into distinct foreground and background stems while preserving the acoustic quality of each component.
Throughout this process, you can monitor the status of your separation task by polling the [`/audio-separation/{task_id}`](get-audio-separation-status) endpoint with the `task_id` provided in your initial response.
## Creating Your First Audio Separation Request
Let's examine how to initiate an audio separation task using Python:
```python [expandable] theme={null}
import requests
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
}
def create_audio_separation(media_file_path):
"""
Submits a new audio separation task and returns the task ID for tracking.
Parameters:
- media_file_path: Path to the audio file you want to separate
"""
try:
# Prepare the multipart form data with the audio file
files = {
"media_file": (media_file_path.split('/')[-1], open(media_file_path, "rb"))
}
# Submit the separation request
response = requests.post(
"https://client.camb.ai/apis/audio-separation",
headers=headers,
files=files
)
# Verify the request was successful
response.raise_for_status()
# Extract the task ID from the response
result = response.json()
task_id = result.get("task_id")
print(f"Audio separation task submitted successfully! Task ID: {task_id}")
return task_id
except requests.exceptions.RequestException as e:
print(f"Error submitting audio separation task: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
# Example usage
audio_path = "path/to/your/audio/file.mp3"
task_id = create_audio_separation(audio_path)
```
## Monitoring Your Separation Progress
After submission, your audio separation task enters our processing pipeline. You can monitor the progress by polling the status endpoint:
```python [expandable] theme={null}
def check_separation_status(task_id):
"""
Checks the status of an audio separation task.
Returns the current status and any available result information.
Parameters:
- task_id: The ID of the separation task to check
"""
if not task_id:
print("No task ID provided.")
return None
try:
response = requests.get(
f"https://client.camb.ai/apis/audio-separation/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Parse the status information
status_data = response.json()
print(f"Current status: {status_data['status']}")
# If the separation is complete, display the results
if status_data['status'] == "SUCCESS":
print("Audio separation completed successfully!")
print(f"Foreground audio URL: {status_data.get('foreground_url')}")
print(f"Background audio URL: {status_data.get('background_url')}")
return status_data
except requests.exceptions.RequestException as e:
print(f"Error checking separation status: {e}")
return None
# Check the status of your separation task
status_info = check_separation_status(task_id)
```
## Supported Audio Formats
Our audio separation system supports a variety of common audio formats to accommodate your workflow needs:
* **FLAC** (Free Lossless Audio Codec) - Ideal for high-quality lossless audio
* **MP3** (MPEG Audio Layer III) - Common compressed format widely supported across platforms
* **WAV** (Waveform Audio File Format) - Uncompressed audio format with excellent quality
* **AAC** (Advanced Audio Coding) - High-quality compressed format commonly used in mobile devices
## Best Practices for Audio Separation
To achieve the highest quality separation results, consider these professional recommendations:
1. **Use High-Quality Sources**: Whenever possible, use uncompressed (WAV) or lossless (FLAC) audio for separation.
2. **Optimal Length**: While the system can handle various durations, files between 10 seconds and 10 minutes typically yield the best results.
3. **Clear Recording**: Audio with minimal background noise, distortion, or heavy effects will separate more cleanly.
4. **Balanced Mix**: Ensure that both foreground and background elements are audible in the original mix for best separation.
5. **Consider Preprocessing**: For challenging audio, consider using noise reduction or equalization before submission to improve separation quality.
# Create a Custom Voice
Source: https://docs.camb.ai/api-reference/endpoint/create-custom-voice
post /create-custom-voice
Creates a new voice clone by uploading an audio file reference.
## Understanding Voice Cloning Technology
This endpoint empowers you to create personalized synthetic voices by leveraging our advanced voice cloning technology. When you submit an audio sample, our system analyzes the unique vocal characteristics of the speaker—including pitch, timbre, rhythm, and other subtle qualities—and generates a digital voice model that can speak any text with those same characteristics. This process effectively "clones" the voice from your sample, enabling you to create custom content that maintains the distinctive vocal identity of the original speaker.
For optimal cloning results:
* Provide a clear, high-quality recording with minimal background noise.
* The audio should feature natural speech patterns at a consistent pace and volume.
* Samples of 30-60 seconds typically provide sufficient data for accurate voice modeling.
## The Voice Cloning Process
When you submit your request to this endpoint, several sophisticated processes occur:
1. **Audio Analysis**: Our system processes your audio file, identifying the core vocal characteristics that make the voice unique.
2. **Feature Extraction**: The system extracts key vocal features, including pitch range, tonal qualities, speech cadence, and articulation patterns.
3. **Voice Model Creation**: These extracted features are used to build a voice model that can synthesize new speech matching the original voice's characteristics.
4. **Voice Registration**: The newly created voice is registered in your account and assigned a unique identifier for future use in text-to-speech operations.
Once complete, your custom voice becomes immediately available for use across our platform.
## Audio Sample Recommendations
The quality of your custom voice depends significantly on the quality of your audio sample. Consider these factors when preparing your sample:
1. **Content Quality**:
* Record in a quiet environment with minimal background noise or echo
* Use a good quality microphone positioned at an appropriate distance
* Maintain consistent volume and speaking pace throughout the recording
* Avoid vocal strains, forced expressions, or unnatural speech patterns
2. **Content Selection**:
* Choose text with diverse phonetic content that exercises different sounds
* Include a variety of sentence structures and intonation patterns
* Select content similar to what you'll ultimately want the voice to produce
* Avoid highly technical terms unless they're essential to your use case
3. **Sample Duration**:
* Aim for 30-60 seconds of clean audio at minimum
* Longer samples (2-3 minutes) can provide better results for more complex use cases
* Very short samples (15 seconds) may produce less consistent voice clones
Following these guidelines will help ensure that the resulting voice clone accurately captures the essence of the original speaker's voice.
## Implementation Example
Here's a comprehensive Python example that demonstrates how to create a custom voice, including proper error handling:
```python [expandable] theme={null}
import requests
import os
import time
def create_custom_voice(file_path, voice_name, gender, age, description=None, language=None):
"""
Creates a custom voice clone from an audio sample
Parameters:
file_path (str): Path to the audio file containing the voice sample
voice_name (str): Name to assign to the custom voice
gender (int): Gender identifier (1=male, 2=female, etc.)
age (int): Approximate age of the speaker
description (str, optional): Detailed description of the voice
language (str, optional): Language code of the voice (e.g., "en-US")
Returns:
dict: Response from the API containing voice details
"""
# Validate file exists
if not os.path.exists(file_path):
raise FileNotFoundError(f"Audio file not found at: {file_path}")
# Prepare file for upload
files = {'file': open(file_path, 'rb')}
# Prepare metadata
data = {
'voice_name': voice_name,
'gender': gender,
'age': age
}
# Add optional parameters if provided
if description:
data['description'] = description
if language:
data['language'] = language
try:
# Make API request
response = requests.post(
"https://client.camb.ai/apis/create-custom-voice",
files=files,
data=data,
headers={
"x-api-key": os.environ.get("API_KEY") # Get API key from environment variable
}
)
# Close file handle
files['file'].close()
# Check for errors
response.raise_for_status()
# Return response data
return response.json()
except requests.exceptions.HTTPError as http_err:
print(f"HTTP error occurred: {http_err}")
if response.text:
print(f"Response details: {response.text}")
return None
except Exception as err:
print(f"Error creating custom voice: {err}")
return None
finally:
# Ensure file is closed even if an error occurs
if 'file' in files and not files['file'].closed:
files['file'].close()
# Example usage
if __name__ == "__main__":
result = create_custom_voice(
file_path="narrator_sample.wav",
voice_name="Professional Narrator",
gender=1,
age=45,
description="Clear, articulate voice with professional tone. Ideal for documentary narration.",
language="en-us" # Locale tag. Numeric IDs (e.g. "1") still work but are deprecated.
)
if result:
print(f"Custom voice created successfully with ID: {result['voice_id']}")
```
## Working with Your Custom Voice
After successfully creating a custom voice, you can use it for various speech synthesis tasks:
1. **Text-to-Speech Conversion**: Use the voice ID with the [`/tts`](create-tts) endpoint to convert text to speech in your custom voice.
2. **Voice Management**: Find your custom voice in the list returned by the [`/list-voices`](list-voices) endpoint, alongside public and shared voices.
3. **Voice Updates**: If needed, you can create a new version of the voice by submitting a new request with the same voice name but a different audio sample.
4. **Voice Publishing**: If you initially created a private voice but later wish to share it, you can use our voice update endpoints to change its publication status.
Custom voices remain associated with your account indefinitely unless explicitly deleted, giving you a persistent library of voices for your various speech synthesis needs.
## Use Cases for Custom Voices
Creating custom voices opens up numerous possibilities for personalized content:
* **Brand Consistency**: Create a consistent voice identity across all your digital touchpoints
* **Character Development**: Build unique voices for characters in games, animations, or interactive experiences
* **Personalized Communication**: Generate content that sounds like a specific individual (with appropriate permissions)
* **Accessibility Solutions**: Create synthetic versions of a person's voice for use in assistive technology
* **Multilingual Content**: Clone a voice and use it to speak multiple languages while maintaining the same vocal identity
By understanding the possibilities, you can better strategize how custom voices might enhance your specific applications and user experiences.
## Ethical Considerations
When creating and using custom voices, please consider these ethical guidelines:
1. Always obtain proper consent from the person whose voice you are cloning
2. Use voice clones respectfully and avoid creating misleading content
3. Clearly identify synthesized speech when there might be confusion about its origin
4. Follow applicable laws and regulations regarding biometric data and privacy
Responsible use of voice cloning technology helps ensure its continued availability while respecting individual rights and social norms.
# Create a Dictionary From File
Source: https://docs.camb.ai/api-reference/endpoint/create-dictionary-from-file
post /dictionaries/create-from-file
This endpoint empowers you to build custom pronunciation and terminology dictionaries by uploading structured data files directly into your CAMB.AI workspace.
What makes this file-based approach particularly valuable is its ability to scale dictionary creation efficiently. Rather than manually entering individual terms one by one, you can prepare comprehensive terminology collections offline using tools your team already knows, then upload complete dictionaries in a single operation. This batch approach becomes essential when working with specialized vocabularies, client-specific terminology, or industry jargon that requires precise handling across multiple audio processing tasks.
## When to Use This Endpoint
Dictionary creation from files serves multiple strategic purposes in your content processing workflow. During project initialization phases, you might upload industry-specific glossaries that ensure consistent pronunciation of technical terms throughout your audio processing operations. When onboarding new clients, their existing terminology databases can be quickly transformed into CAMB.AI dictionaries that maintain brand consistency and domain expertise across all subsequent processing tasks.
The file-based approach excels when you're working with collaborative teams where subject matter experts can contribute terminology knowledge without needing direct access to the CAMB.AI platform. Rather than recreating extensive vocabulary collections manually, you can preserve existing organizational knowledge by transforming it into CAMB.AI-compatible formats and uploading it as structured dictionary resources.
## File Format Requirements and Structure
The endpoint accepts both CSV and Excel file formats, providing flexibility for teams that work with different data preparation tools. Understanding the required structure becomes crucial for successful dictionary creation, as the system expects specific column arrangements and data formatting that enable proper term recognition and pronunciation guidance.
Your dictionary file must follow a structured [format](https://storage.googleapis.com/cambai-prod-public/dictionary/sample.xlsx) where each row represents a distinct term or pronunciation rule, and specific columns contain the information necessary for the AI systems to understand how to process that term.
## Long-term Dictionary Management Considerations
File-based dictionary creation establishes the foundation for ongoing terminology resource management that evolves with your organizational needs and processing experience. Understanding how initial dictionary creation connects to long-term maintenance workflows helps you make strategic decisions about file organization and content structure that support sustainable terminology management practices.
# Create Folder
Source: https://docs.camb.ai/api-reference/endpoint/create-folder
post /folders/create
Establish organizational containers within your CAMB.AI workspace to structure audiobook projects effectively. This endpoint creates the foundational filing system that enables efficient project management and team collaboration across your growing content library.
## Overview
Folders serve as the organizational backbone of your CAMB.AI workspace, functioning as digital filing cabinets that contain and categorize your audiobook projects. These containers become increasingly valuable as your content library expands, providing the structural foundation that transforms chaotic project lists into navigable, logical hierarchies that support both individual productivity and collaborative workflows.
The Create Folder endpoint addresses a fundamental workspace management need by establishing these organizational containers before project creation, enabling you to implement consistent categorization strategies that scale effectively as your audiobook production grows from individual projects to comprehensive content libraries.
## When to Create Folders
Strategic folder creation occurs at multiple points in your workflow evolution. During initial workspace setup, you'll establish foundational organizational structures that reflect your content strategy and production approach. As your library grows, you'll create specialized folders that accommodate new content categories, collaboration partnerships, or workflow refinements that emerge from operational experience.
The endpoint proves particularly valuable when implementing systematic project organization strategies. Rather than creating projects first and organizing them later, proactive folder creation enables immediate categorization that maintains structural clarity throughout your production pipeline.
## Implementation and Response Structure
Creating folders requires minimal configuration while providing comprehensive feedback for workflow integration. The endpoint accepts a simple folder name and returns complete organizational information including the unique folder identifier needed for subsequent project assignments.
```python [expandable] theme={null}
import requests
import json
headers = {
"x-api-key": "your-api-key",
"Content-Type": "application/json"
}
def create_project_folder(folder_name):
"""Establishes a new organizational container for audiobook projects"""
try:
response = requests.post(
"https://client.camb.ai/apis/folders/create",
headers=headers,
json={"folder_name": folder_name}
)
response.raise_for_status()
result = response.json()
print(f"Created folder '{result.get('folder_name')}' with ID: {result.get('folder_id')}")
return result
except requests.exceptions.RequestException as e:
print(f"Folder creation failed: {e}")
return None
# Strategic folder creation for audiobook organization
organizational_folders = [
"Fiction - Mystery Series",
"Educational Content - Science",
"Corporate Training - Q2 2024"
]
for folder_name in organizational_folders:
create_project_folder(folder_name)
```
## Strategic Integration with Project Workflows
The Create Folder endpoint integrates seamlessly with broader project management strategies by establishing organizational foundations before project creation. This proactive approach ensures that audiobook projects inherit appropriate categorization from inception, eliminating the need for retrospective organization that often leads to inconsistent project structures.
Effective folder creation considers both immediate organizational needs and long-term scalability requirements. Folders created with strategic naming conventions and clear categorization logic provide lasting value that compounds as your workspace grows, supporting efficient project discovery and collaborative access patterns that enhance rather than complicate your creative workflows.
Understanding folder creation as a foundational workspace management activity enables more sophisticated organizational strategies that support complex audiobook production pipelines while maintaining the simplicity needed for efficient daily operations.
# Setup Project
Source: https://docs.camb.ai/api-reference/endpoint/create-project-setup
post /project-setup
Initialize dubbing projects through the API for seamless editing and management in CAMB.AI Studio. This endpoint creates the foundation for your dubbing workflow by analyzing source media and establishing optimal configuration parameters.
Bridge the gap between API automation and hands-on creative control with our Project Setup endpoint. This powerful tool allows you to programmatically initialize dubbing projects that seamlessly integrate with CAMB.AI Studio, giving you the best of both worlds: automated project creation through your existing workflows and the flexibility to fine-tune results through our visual interface.
Think of this endpoint as your content's intelligent onboarding system. It analyzes your media, validates configurations, and creates a fully-prepared project ready for detailed editing in CAMB.AI Studio. This approach transforms how content teams work, enabling developers to handle project initialization while creative professionals focus on perfecting the final output.
## Why Project Setup Matters for API Users
The traditional dubbing workflow often creates friction between technical teams managing content pipelines and creative teams perfecting the final product. Project Setup eliminates this friction by establishing a clear handoff point where technical configuration meets creative refinement.
When you submit a project through this endpoint, you're not just uploading media—you're creating a structured workspace in CAMB.AI Studio that contains all the analysis, configuration, and preparation work needed for efficient dubbing. Your creative team receives a project that's already optimized and ready for detailed editing, rather than starting from scratch with raw media files.
## The API-to-Studio Workflow
Understanding how Project Setup connects API automation with Studio editing helps you design more efficient content workflows. The process creates a seamless bridge between programmatic project creation and visual editing tools.
**Automated Project Initialization**: Your API request handles all the technical groundwork—media analysis, language configuration, and optimization parameter selection. This automation ensures consistent project setup across your entire content library while eliminating manual configuration errors.
**Studio-Ready Project Creation**: The endpoint generates a fully-prepared project workspace in CAMB.AI Studio, complete with analyzed audio tracks, configured language settings, and optimized processing parameters. Your creative team can immediately begin working with the content rather than spending time on technical setup.
**Preserved Configuration Context**: All API-specified parameters, including custom dictionaries and advanced audio track settings, carry forward into the Studio environment. This continuity ensures that your technical requirements remain intact while enabling creative refinement.
## Media Source Compatibility
Project Setup accommodates diverse media sources, making it easy to integrate with existing content management systems. Whether your media lives on YouTube, Google Drive, or professional storage systems, the endpoint handles ingestion automatically.
The system supports both consumer formats like MP4 and professional broadcast formats including MXF files for Enterprise customers. This broad compatibility means you can standardize your project creation process regardless of your content's origin or quality level.
Enterprise plan customers enjoy exclusive access to MXF format support, bringing professional broadcast standards to organizations with specialized media requirements.
## Implementation Example
Let's examine how to create a project that leverages both API efficiency and Studio flexibility. This example demonstrates the essential parameters while showing how your configuration translates into a Studio-ready workspace.
```python [expandable] theme={null}
import requests
import json
# Configure API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
# Define project configuration
# This setup creates a project optimized for Studio editing
project_config = {
"project_name": "Product Launch Campaign", # Project name visible in Studio
"project_description": "Multi-language product demo for global markets", # Context for Studio users
"media_url": "https://your-storage.com/product-demo.mp4", # Source media location
"source_language": "en-us", # Locale tag. Numeric IDs (e.g. 1) still work but are deprecated.
"target_languages": ["es-es", "fr-fr", "de-de"],
}
def create_studio_project(payload):
"""
Creates a project configured for optimal Studio editing experience.
The resulting project appears in CAMB.AI Studio with all technical setup complete.
"""
try:
response = requests.post(
"https://client.camb.ai/apis/project-setup",
headers=headers,
data=json.dumps(payload)
)
response.raise_for_status()
result = response.json()
task_id = result.get("task_id")
return task_id
except requests.exceptions.RequestException as e:
print(f"Project creation failed: {e}")
return None
# Create the project
project_setup_task_id = create_studio_project(project_config)
if not project_setup_task_id:
print(f"Failed to create project '{project_config['project_name']}'. Please check your API key and configuration.")
else:
print(f"Project '{project_config['project_name']}' task is created successfully! Task ID: {project_setup_task_id}")
```
## Best Practices for API-Studio Integration
Successful integration between API project creation and Studio editing depends on understanding how your configuration choices impact the creative editing experience. Several strategies can significantly improve your team's efficiency and output quality.
**Descriptive Project Naming**: Use clear, descriptive names and descriptions that help Studio users understand project context immediately. This clarity becomes crucial when managing multiple projects or coordinating between team members with different responsibilities.
**Optimal Language Configuration**: Verify locale tags using the dedicated endpoints before submitting projects. Accurate language configuration ensures that Studio users receive projects with properly configured voice options and translation models.
**Quality-Focused Media Selection**: Choose the highest quality source media available, as compression artifacts and audio issues in source material become more apparent during the detailed editing process in Studio. Starting with quality media enables better creative decisions throughout the editing workflow.
Project Setup represents the ideal fusion of API automation and creative control. By handling the technical groundwork programmatically, you enable your creative team to focus on the nuanced decisions that determine final quality, while ensuring consistent, professional results across your entire content pipeline.
# Create Story
Source: https://docs.camb.ai/api-reference/endpoint/create-story
post /story
Creates a story based on the content provided in a text file (`.txt`) or Word document (`.docx`)
Transform your written content into engaging narrated stories with our story creation endpoint. This powerful service takes your text documents and processes them into compelling stories with professional narration. The system handles the entire process from parsing your document to generating a professionally narrated version, making storytelling accessible.
## The Story Creation Process
When you submit a story creation request, our system begins a multi-stage workflow:
Your uploaded text file or Word document is processed and prepared for narration. Our system extracts and analyzes the content, ensuring proper formatting and structure.
Your chosen AI narrator voice is applied to the story, bringing your content to life with natural-sounding speech patterns and appropriate emotional delivery.
The narration is finalized with professional audio quality enhancements, ensuring clarity and engagement.
Throughout this process, you can check on your task's progress using the [`/story/{task_id}`](get-story-status) endpoint with the `task_id` provided in your initial response.
## Supported Document Formats
Our story creation service accepts two popular document formats to accommodate your workflow:
| Document Type | Supported Formats |
| :------------- | :---------------- |
| Text Files | .txt |
| Word Documents | .docx |
This flexibility allows you to work with your preferred writing tools without conversion hassles.
## Language Configuration
Specifying the correct source language is crucial for successful story creation. To find the appropriate language identifier:
1. Query the [`/source-languages`](get-source-languages) endpoint for a complete list of supported languages.
2. Pass the locale tag (e.g. `"en-us"`) in your request. Numeric language IDs still work but are deprecated.
## Creating Your First Story
Let's look at how to initiate a story creation task with Python:
```python [expandable] theme={null}
import requests
import json
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
}
# Define your story parameters
title = "The Midnight Garden"
description = "A mysterious tale of discovery and wonder"
source_language = "en-us" # Locale tag. Numeric IDs (e.g. 1) still work but are deprecated. See /source-languages.
narrator_voice_id = 147320 # Example
# Function to submit a story creation request
def create_story(file_path, title, description, source_language, narrator_voice_id):
"""
Submits a new story creation task and returns the task ID for tracking.
Parameters:
- file_path: Path to the .txt or .docx file containing story content
- title: Title of the story
- description: Brief description of the story
- source_language: Locale tag (e.g. "en-us") for the story content; numeric IDs still work but are deprecated
- narrator_voice_id: ID of the voice that will narrate the story
"""
try:
# Prepare the multipart form data
files = {
'file': (file_path.split('/')[-1], open(file_path, 'rb'))
}
data = {
'title': title,
'description': description,
'source_language': source_language,
'narrator_voice_id': narrator_voice_id
}
# Submit the request
response = requests.post(
"https://client.camb.ai/apis/story",
headers=headers,
files=files,
data=data
)
# Verify the request was successful
response.raise_for_status()
# Extract the task ID from the response
result = response.json()
task_id = result.get("task_id")
print(f"Story creation task submitted successfully! Task ID: {task_id}")
return task_id
except requests.exceptions.RequestException as e:
print(f"Error submitting story creation task: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
finally:
# Make sure to close the file
if 'files' in locals() and 'file' in files:
files['file'][1].close()
# Call the function with your story file
file_path = "path/to/your/story.docx" # Replace with your actual file path
task_id = create_story(file_path, title, description, source_language, narrator_voice_id)
```
## Monitoring Your Story Creation Progress
After submission, your content enters our processing pipeline. The time required depends on the length and complexity of your document. You can check progress by polling the status endpoint:
```python [expandable] theme={null}
def check_story_status(task_id):
"""
Checks the status of a story creation task.
Returns the current status and any available result information.
Parameters:
- task_id: The ID of the story creation task to check
"""
if not task_id:
print("No task ID provided.")
return None
try:
response = requests.get(
f"https://client.camb.ai/apis/story/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Parse the status information
status_data = response.json()
print(f"Current status: {status_data['status']}")
# If the story is complete, display the results
if status_data['status'] == "SUCCESS":
print("Story creation completed successfully!")
print(f"Story URL: {status_data.get('story_url')}")
return status_data
except requests.exceptions.RequestException as e:
print(f"Error checking story status: {e}")
return None
# Check the status of your story creation task
status_info = check_story_status(task_id)
```
## Best Practices for Optimal Results
To get the most from our story creation service, consider these professional tips:
1. **Document Quality**: Ensure your document is well-formatted with proper grammar and punctuation for better narration results.
2. **Voice Selection**: Choose a narrator voice that matches the tone and style of your story content.
3. **Language Accuracy**: Double-check that your source language is correctly specified to ensure proper pronunciation and pacing.
4. **Content Length**: While our system can handle documents of various lengths, consider breaking very long works into logical segments for optimal processing.
5. **File Format**: Use .docx format when you need to preserve complex formatting, and .txt for simpler text-based stories.
## Practical Applications
Our story creation functionality opens exciting possibilities across industries:
* **Education**: Transform educational content into engaging audio lessons for diverse learning styles.
* **Publishing**: Quickly create audio versions of books, articles, and short stories.
* **Content Creation**: Convert blog posts and articles into narrated content for podcasts or audio platforms.
* **Accessibility**: Make written content accessible to visually impaired audiences or those who prefer audio content.
* **Entertainment**: Bring original stories to life with professional-quality narration.
By integrating this API into your workflow, you can efficiently transform written content into engaging audio stories, dramatically reducing the time and expense traditionally associated with professional narration while maintaining impressive quality.
# Setup Story
Source: https://docs.camb.ai/api-reference/endpoint/create-story-setup
post /story-setup
Initialize audiobook projects through the API for seamless editing and management in CAMB.AI Studio. This endpoint creates the foundation for your stories workflow by analyzing source text and establishing optimal narration parameters.
Transform your written content into professional audiobook projects with our Story Setup endpoint. This intelligent service bridges the gap between automated project initialization and creative audiobook production, allowing you to programmatically create story projects that seamlessly integrate with CAMB.AI Studio for detailed narration refinement and management.
Story Setup differs from direct story creation by building a project workspace rather than producing immediate results. Think of it as preparing a professional editing suite where creative teams can adjust pacing, refine pronunciation, and enhance overall audiobook quality.
## How it Works
Story Setup handles the technical foundation while preserving creative control. Your API request processes text analysis, configures narrator settings, and creates a Studio workspace with all preparation complete. Creative teams receive a ready-to-edit project rather than starting from raw text files.
The workflow naturally divides responsibilities between automated setup and creative refinement, enabling consistent project initialization while maintaining the flexibility needed for high-quality audiobook production.
## Quick Implementation
```python [expandable] theme={null}
import requests
headers = {"x-api-key": "your-api-key"}
def create_audiobook_project(file_path, title, description, source_language, narrator_voice_id):
"""Creates audiobook project workspace in CAMB.AI Studio"""
files = {'file': open(file_path, "rb")}
data = {
'title': title,
'description': description,
'source_language': source_language,
'narrator_voice_id': narrator_voice_id
}
try:
response = requests.post(
"https://client.camb.ai/apis/story-setup",
headers=headers, files=files, data=data
)
response.raise_for_status()
result = response.json()
print(f"Project created! Studio URL: {result.get('story_details', {}).get('studio_url')}")
return result.get("run_id")
except requests.exceptions.RequestException as e:
print(f"Creation failed: {e}")
return None
finally:
files['file'].close()
# Example usage
run_id = create_audiobook_project(
"story.docx", # Replace with your local file path you are uploading.
"My Audiobook Project",
"Adventure story requiring dramatic narration",
1, # English
147320
)
```
## Essential Configuration
Use clear project names and detailed descriptions to help Studio editors understand your content context and narration requirements. Verify language settings using the source languages endpoint and select narrator voices that match your content's tone and target audience.
Prepare documents with proper formatting and structure, as chapter organization and text quality directly impact the editing workflow. For specialized content with unique terminology, consider preparing pronunciation dictionaries to ensure consistent narration.
## When to Choose Story Setup
Use Story Setup for collaborative audiobook projects requiring creative refinement, quality control, or complex narration requirements. This endpoint excels when audiobook quality and team collaboration matter more than immediate results.
For simple, immediate narrated content without extensive editing needs, consider direct story creation instead. Story Setup provides the foundation for professional audiobook production where creative control and collaborative workflows drive the final quality.
# Create Subtitle
Source: https://docs.camb.ai/api-reference/endpoint/create-subtitle
post /sub
Creates a task to generate subtitle-ready segments from a media URL, in the source language and any number of target languages. Send a JSON body with a publicly accessible or signed media URL.
## Generating Subtitles Across Languages
Our subtitle service turns spoken media into cue-ready text. It transcribes the source language, translates into any target languages you request, and, when you ask for it, segments every language into cues sized for on-screen display. This endpoint initiates a subtitle task from a media URL and returns a unique identifier that allows you to track and retrieve your results.
## Understanding Subtitle Generation
Subtitle generation builds on the same speech recognition and translation technology behind our Transcription and Translation services, chained together for you in a single request:
1. Analyzes the media to identify speech segments in the source language
2. Translates the recognized speech into each requested target language
3. When `formatting_options` is provided, segments every language's text into cues that respect subtitle timing and length limits
This lets you go from a raw recording to subtitles in several languages without orchestrating transcription, translation, and segmentation as separate calls.
## Language Selection
Subtitle generation needs `source_language` and a non-empty `target_languages` array in the JSON body:
* **`source_language`**: the language spoken in your media. Locale tag (e.g. `en-us`) or numeric ID.
* **`target_languages`**: one or more output languages. Pass a single-item array when you only need one language (for example `["es-es"]`), the same pattern as end-to-end dubbing.
Include the source language itself in `target_languages` if you also want same-language, subtitle-ready cues for the original speech.
For a complete list of supported languages and their locale tags, see [source languages](get-source-languages) and [target languages](get-target-languages).
### Supported Media Formats
Provide a publicly accessible or signed `media_url`. For optimal results, we recommend using high-quality media with clear speech and minimal background noise. Our service accepts the following media formats:
* MP3 (`.mp3`)
* WAV (`.wav`)
* AAC (`.aac`)
* FLAC (`.flac`)
* MP4 (`.mp4`)
* MOV (`.mov`)
* MXF (`.mxf`)
Please note that MXF format support is exclusively available to customers on our Enterprise plan, offering professional broadcast-quality media handling for organizations with advanced needs.
## Transcription Mode
The optional `transcription_mode` field controls the transcription pass used for the source media:
* **`fast`** (default): returns a result more quickly while maintaining quality.
* **`slow`**: takes longer and may produce a more accurate transcript through a more thorough pass.
Omit the field to use `fast`.
## Subtitle Formatting
By default, subtitle generation translates the source speech into each target language but leaves the text unsegmented, the same speech-boundary segments you'd get from Translation, not subtitle-length cues. To get cues sized for on-screen subtitles, pass the optional `formatting_options` object in the JSON body. When provided, subtitle segmentation runs for every requested language:
* **`max_segment_duration_in_seconds`** (default: `7.0`): the longest a single cue may stay on screen.
* **`min_segment_duration_in_seconds`** (default: `1.0`): the shortest a single cue may stay on screen.
* **`max_characters_in_segment`** (default: `42`): the maximum number of characters allowed in one cue.
Omit `formatting_options` if you just need translated dialogue without subtitle timing rules.
```bash [expandable] theme={null}
curl -X POST "https://client.camb.ai/apis/sub" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_language": "en-us",
"media_url": "https://example.com/interview.mp4",
"target_languages": ["es-es", "fr-fr"],
"transcription_mode": "fast",
"formatting_options": {
"max_segment_duration_in_seconds": 7,
"min_segment_duration_in_seconds": 1,
"max_characters_in_segment": 42
}
}'
```
## Request Example
Create a subtitle task by sending a JSON body with a media URL. Here's how to request subtitles in multiple target languages using Python with the `requests` library:
```python [expandable] theme={null}
import json
import requests
def create_subtitle_task(
api_key,
media_url,
source_language="en-us",
target_languages=None,
formatting_options=None,
):
"""
Initiates a subtitle task from a media URL.
Args:
api_key (str): API authentication key
media_url (str): Public or signed URL of the media resource
source_language (str): Locale tag like "en-us"; numeric IDs still work but are deprecated
target_languages (list[str]): Locale tags for one or more target languages
formatting_options (dict, optional): Subtitle segmentation rules, e.g.
{"max_segment_duration_in_seconds": 7, "min_segment_duration_in_seconds": 1, "max_characters_in_segment": 42}
Returns:
dict: Response containing task_id for status tracking
"""
url = "https://client.camb.ai/apis/sub"
headers = {
"x-api-key": api_key,
"Content-Type": "application/json",
}
payload = {
"source_language": source_language,
"media_url": media_url,
"target_languages": target_languages or [],
"transcription_mode": "fast",
}
if formatting_options:
payload["formatting_options"] = formatting_options
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.ok:
return response.json()
print(f"Error {response.status_code}: {response.text}")
return None
# Request subtitles in Spanish and French, with subtitle-ready cues
result = create_subtitle_task(
api_key="your_api_key",
source_language="en-us",
target_languages=["es-es", "fr-fr"],
media_url="https://storage.example.com/interview.mp3",
formatting_options={
"max_segment_duration_in_seconds": 7,
"min_segment_duration_in_seconds": 1,
"max_characters_in_segment": 42,
},
)
```
Optional body fields include `project_name`, `project_description`, and `folder_id`.
## Next Steps: Monitoring Your Subtitle Task
After submitting your subtitle request, you'll want to monitor its progress and retrieve the results once processing completes:
1. Use the [`/sub/{task-id}`](poll-subtitle-result) endpoint to check your task's status
2. Poll the status endpoint at reasonable intervals (we recommend 5-15 second intervals for most cases)
3. Once the status shows as `SUCCESS`, retrieve your subtitles from [`/sub-result/{run_id}`](get-subtitle-run-result) (every language; optional `format_type`/`data_type` export) or [`/sub-result/{run_id}/{language}`](get-subtitle-result-for-language) for one language
Need a plain transcript in a single language instead of translated, multi-language subtitles? Use [Create Transcription](create-transcription). It shares the same `formatting_options` field for subtitle-ready cues.
# Create Sound and Music
Source: https://docs.camb.ai/api-reference/endpoint/create-text-to-sound
post /text-to-sound
Creates a task to generate an audio file—either music or sound effects—from a given text prompt
Turn descriptive text into expressive music or sound effects. This endpoint generates either structured musical audio (melodies, harmonies, beats) or non-musical SFX (foley, UI beeps, ambience, impacts) based on your prompt and selected `audio_type`.
## The Generation Process
Your request is registered and a processing task is created. The response includes a unique `task_id` you’ll use to track progress and retrieve results (via the returned `run_id`).
We analyze your prompt to identify sonic intent—musical attributes (tempo, instrumentation, groove) for `music`, or acoustic characteristics (materials, space, motion) for `sound`.
Specialized models synthesize the audio to match your description and requested `duration`.
* **Music `duration` behavior:**
When `audio_type` is set to `music`, the `duration` parameter is **not enforced**. Music generations currently return a fixed-length clip depending on the prompt provided. If you need a precise length for music, trim, loop, or stitch the result in post-production. The `duration` parameter continues to apply to `sound` (SFX) requests.
Maximum duration per request is **10 seconds**. The default duration is **8.0 seconds**.
Throughout this process, you can monitor the status of your generation task by polling the [`/text-to-sound/{task_id}`](get-text-to-sound-status) endpoint with the `task_id` provided in your initial response.
## Creating Your First Request
Let's examine how to initiate a sound generation task using Python:
```python [expandable] theme={null}
import requests
import json
from typing import Literal
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def create_text_to_sound(prompt: str, audio_type: Literal["sound", "music"], duration=8.0):
"""
Submits a new text-to-sound generation task and returns the task ID for tracking.
Parameters:
- prompt: A descriptive text explaining the sound to generate
- duration: The desired length of the audio in seconds (default: 8.0)
"""
try:
# Prepare the request body
payload = {
"prompt": prompt,
"duration": duration,
"audio_type": audio_type
}
# Submit the generation request
response = requests.post(
"https://client.camb.ai/apis/text-to-sound",
headers=headers,
data=json.dumps(payload)
)
# Verify the request was successful
response.raise_for_status()
# Extract the task ID from the response
result = response.json()
task_id = result.get("task_id")
print(f"Sound generation task submitted successfully! Task ID: {task_id}")
return task_id
except requests.exceptions.RequestException as e:
print(f"Error submitting text-to-sound task: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
# SFX example
prompt = "A gentle rainfall on a tin roof that swells briefly with a distant thunder roll"
task_id = create_text_to_audio(prompt, audio_type="sound", duration=10.0)
# Music example
prompt = "Warm lo-fi beat at 80 BPM with soft piano chords, vinyl crackle, and mellow bass"
task_id = create_text_to_audio(prompt, audio_type="music")
```
## Monitoring Your Sound Generation Progress
After submission, your sound generation task enters our processing pipeline. You can monitor the progress by polling the status endpoint:
```python [expandable] theme={null}
def check_sound_generation_status(task_id):
"""
Checks the status of a text-to-sound generation task.
Returns the current status and any available result information.
Parameters:
- task_id: The ID of the generation task to check
"""
if not task_id:
print("No task ID provided.")
return None
try:
response = requests.get(
f"https://client.camb.ai/apis/text-to-sound/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Parse the status information
status_data = response.json()
print(f"Current status: {status_data['status']}")
# If the generation is complete, display the results
if status_data['status'] == "SUCCESS":
print("Sound generation completed successfully!")
print(f"Audio URL: {status_data.get('audio_url')}")
return status_data
except requests.exceptions.RequestException as e:
print(f"Error checking generation status: {e}")
return None
# Check the status of your generation task
status_info = check_sound_generation_status(task_id)
```
## Prompting Tips
The quality of your generated audio depends significantly on how well you craft your text prompts. Here are some professional recommendations for creating effective descriptions:
1. **Be Specific**:
* **Music**: “Upbeat indie rock with clean electric guitars, driving drums, and a catchy 4-bar hook.”
* **SFX**: “Single metal door slam in a concrete hallway, short decay, slight echo.”
2. **Include Context**:
* **Music**: “Mellow coffee-shop background loop, no vocals, relaxed vibe.”
* **SFX**: “Footsteps on wet gravel at night, occasional splashes.”
3. **Describe Dynamics**:
* **Music**: “8-second loop, soft intro hit, steady groove, light ending tail.”
* **SFX**: “Starts distant, approaches quickly, then passes left to right.”
4. **Mention Emotional Qualities**:
* **Music**: “Dreamy and nostalgic, lo-fi texture, gentle swing.”
* **SFX**: “Eerie, tense drone with subtle mechanical whir.”
5. **Reference Familiar Sounds**:
* **Music**: “Similar to a chillhop beat with muted trumpet accents.”
* **SFX**: “Like a UI success chime with a soft shimmer tail.”
# Create Voice from Description
Source: https://docs.camb.ai/api-reference/endpoint/create-text-to-voice
post /text-to-voice
Submits a request to initiate a task for creating a human-like voice from a given text prompt.
This endpoint enables you to generate custom, human-like synthetic voices based on your descriptive text prompts. Rather than selecting from pre-defined voice options, this innovative approach allows you to craft voices tailored to your specific needs by simply describing the voice characteristics you want. The endpoint initiates an asynchronous process, returning a task\_id that you can use to monitor the generation progress and eventually retrieve your custom voice.
A description consisting of at least 18 words (100+ characters) is required for voice generation. Requests with shorter prompts will not be processed successfully.
## How Voice Generation Works
The voice generation process follows these steps:
1. You submit a detailed description of the voice you want to create, along with sample text for the voice to speak.
2. The system analyzes your description and generates two sample voices matching those characteristics for you to choose from.
3. The system returns a `task_id` that you can use to track the generation process.
4. You periodically check the status using the [`/text-to-voice/{task_id}`](get-text-to-voice-status) endpoint.
5. Once complete, you can access and use the generated voice in your applications.
## Creating Effective Voice Descriptions
The quality and specificity of your voice description directly impacts the resulting voice. When crafting your description, consider including details about:
* **Gender and age range**: "A middle-aged woman" or "An elderly man"
* **Accent and regional characteristics**: "With a mild Scottish accent" or "Speaking American English with Southern inflections"
* **Emotional qualities**: "A warm, nurturing tone" or "An authoritative, confident delivery"
* **Speaking style**: "Who speaks slowly and deliberately" or "With an energetic, rapid-fire delivery"
* **Cultural context**: "A voice that would be at home narrating documentaries" or "Like a friendly teacher explaining concepts"
* **Vocal characteristics**: "With a slightly raspy quality" or "With a deep, resonant tone"
The more detailed and vivid your description, the more precisely the system can match your desired voice characteristics. Remember that your description must contain at least 18 words (100+ characters) to provide sufficient guidance for the voice generation system.
## Example Request
```json theme={null}
{
"text": "Welcome to our application. I'll be your guide through all the features and capabilities available to you.",
"voice_description": "A warm and friendly middle-aged woman with a slight British accent. She speaks clearly and articulately, with a soothing tone that conveys expertise and trustworthiness. Her voice has a natural musical quality without being overly dramatic."
}
```
## Response
Upon successful submission, the endpoint returns a `task_id` that you can use to check the status of your voice generation task:
```json theme={null}
{
"task_id": "your_task_id"
"status": "PENDING"
}
```
## Monitoring Generation Progress
Voice generation is a computationally intensive process that typically takes some time to complete. To check the status of your generation task, periodically poll the [`/text-to-voice/{task_id}`](get-text-to-voice-status) endpoint using the `task_id` received in the initial response.
## Best Practices
1. **Be specific in your descriptions**: The more detailed your voice description, the better the system can match your expectations.
2. **Consider the context**: Tailor your voice to match the content and audience of your application.
3. **Start with longer descriptions**: While 18 words is the minimum, starting with more detailed descriptions (30-50 words) often yields better results.
4. **Test variations**: If your first voice isn't exactly what you need, try adjusting specific aspects of your description to refine the results.
5. **Include emotional context**: Describing the emotional quality of the voice significantly improves the naturalness of the generated speech.
## Limitations
* Voice descriptions must be at least 18 words (100+ characters) long.
* Very unusual or contradictory voice descriptions may yield unpredictable results.
By leveraging this endpoint effectively, you can create custom voices that perfectly match your brand identity, content needs, and user expectations, all without the need for professional voice talent or recording studios.
# Create Transcription
Source: https://docs.camb.ai/api-reference/endpoint/create-transcription
post /transcribe
Creates a task to process speech into readable text. Submit either a media file or a publicly accessible media URL. Optionally request subtitle-ready segmentation on the resulting transcript.
## Converting Speech to Text with Precision
Our transcription service transforms spoken content into accurate, readable text, enabling you to make your media content searchable, accessible, and analytically valuable. This endpoint initiates a transcription task, processing your media file and returning a unique identifier that allows you to track and retrieve your results.
## Understanding Speech Transcription
Speech transcription technology analyzes media recordings of human speech or video that contains speech and converts them into written text. This process employs sophisticated machine learning models trained on diverse speech patterns, accents, and linguistic contexts to deliver high-quality text outputs. Our system handles various media formats and speaking situations, from clear studio recordings to more challenging environments with background noise.
When you submit a media file for transcription, our system:
1. Analyzes the audio signal to identify speech segments
2. Processes these segments through advanced recognition models
3. Applies language-specific rules and context awareness
4. Generates a readable text transcript that captures the spoken content
This transformation creates valuable text assets from your media content, enabling new ways to search, analyze, and repurpose your spoken material.
### Supported Languages
Our transcription service supports a wide range of languages. Some of the most commonly used include:
* English (`en-us`)
* Spanish (`es-es`)
* French (`fr-fr`)
* German (`de-de`)
* Mandarin Chinese (`zh-cn`)
* Japanese (`ja-jp`)
* Arabic (`ar-sa`)
For a complete list of supported languages and their respective language codes, refer to our Language Support Documentation
### Supported media Formats
For optimal transcription quality, we recommend using high-quality media with clear speech and minimal background noise. Our service accepts the following media formats:
* MP3 (`.mp3`)
* WAV (`.wav`)
* AAC (`.aac`)
* FLAC (`.flac`)
* MP4 (`.mp4`)
* MOV (`.mov`)
* MXF (`.mxf`)
Please note that MXF format support is exclusively available to customers on our Enterprise plan, offering professional broadcast-quality media handling for organizations with advanced needs.
## Transcription Mode
The optional `transcription_mode` form field controls the transcription pass used for the source media:
* **`fast`** (default): returns a transcript more quickly while maintaining quality.
* **`slow`**: takes longer and may produce a more accurate transcript through a more thorough pass.
Omit the field to use `fast`.
## Keeping Music in the Foreground
The optional `include_music_in_fg` form field controls how background music is handled during source separation:
* **`true`** (default): music is preserved in the foreground audio alongside speech.
* **`false`**: music is stripped out of the foreground, isolating speech.
Omit the field to keep the default behaviour of retaining music.
## Subtitle-Ready Segmentation
By default, a transcript is segmented by natural speech patterns rather than by subtitle-length rules. If you're planning to export the transcript as `srt`/`vtt`, or just need shorter, screen-friendly cues, pass the optional `formatting_options` form field. It's a JSON string on the multipart request. When provided, subtitle segmentation also runs on the completed transcript, in the same language:
* **`max_segment_duration_in_seconds`** (default: `7.0`): the longest a single segment may stay on screen.
* **`min_segment_duration_in_seconds`** (default: `1.0`): the shortest a single segment may stay on screen.
* **`max_characters_in_segment`** (default: `42`): the maximum number of characters allowed in one segment.
Omit `formatting_options` for a standard, speech-boundary transcript.
```bash [expandable] theme={null}
curl -X POST "https://client.camb.ai/apis/transcribe" \
-H "x-api-key: YOUR_API_KEY" \
-F "language=en-us" \
-F "media_url=https://example.com/interview.mp4" \
-F 'formatting_options={"max_segment_duration_in_seconds": 7, "min_segment_duration_in_seconds": 1, "max_characters_in_segment": 42}'
```
Need subtitles in languages other than the source, or want to fetch cues per target language? Use the dedicated [Create Subtitle](create-subtitle) endpoint instead. It runs the same segmentation on translated output for one or more target languages.
## Request Example
You can create a transcription task by either uploading a media file or providing a URL to a media resource. Here are examples using cURL:
* Using a local media file:
```bash [expandable] theme={null}
curl -X POST "https://client.camb.ai/apis/transcribe" \
-H "x-api-key: YOUR_API_KEY" \
-F "language=en-us" \
-F "include_music_in_fg=true" \
-F "media_file=@/path/to/your/media_file.mp3"
```
* Using a remote media URL:
```bash [expandable] theme={null}
curl -X POST "https://client.camb.ai/apis/transcribe" \
-H "x-api-key: YOUR_API_KEY" \
-F "language=en-us" \
-F "media_url=https://example.com/media_file.mp3"
```
Here's how to handle both scenarios in Python with the `requests` library:
```python [expandable] theme={null}
import requests
def create_transcription_task(api_key, language="en-us", media_file_path=None, media_url=None):
"""
Initiates a transcription task using either a media file or URL.
Args:
api_key (str): API authentication key
language (str): Locale tag like "en-us"; numeric IDs (e.g. 1) still work but are deprecated
media_file_path (str, optional): Path to local media file
media_url (str, optional): URL of remote media resource
Returns:
dict: Response containing task_id for status tracking
"""
url = "https://client.camb.ai/apis/transcribe"
headers = {"x-api-key": api_key}
data = {"language": language, "transcription_mode": "fast"}
files = None
# Validate input
if not (media_file_path or media_url):
raise ValueError("Must provide either media_file_path or media_url")
if media_file_path and media_url:
raise ValueError("Provide only one of media_file_path or media_url")
# Prepare request components
if media_file_path:
with open(media_file_path, "rb") as media_file:
files = {"media_file": (media_file_path.split("/")[-1], media_file)}
else:
data["media_url"] = media_url
# Execute request
response = requests.post(url, headers=headers, files=files, data=data)
if response.ok:
return response.json()
else:
print(f"Error {response.status_code}: {response.text}")
return None
# Example with file upload
file_result = create_transcription_task(
api_key="your_api_key",
media_file_path="meeting_recording.mp3",
language="en-us"
)
# Example with media URL
url_result = create_transcription_task(
api_key="your_api_key",
media_url="https://storage.example.com/interview.mp3",
language="es-es"
)
```
## Processing Time Considerations
Transcription processing time depends on several factors:
* **Media Duration**: Longer files naturally take more time to process
* **Media Quality**: Clear, high-quality recordings process more efficiently
* **Language Complexity**: Some languages may require more processing time
* **System Load**: Processing time can vary based on current system demand
## Next Steps: Monitoring Your Transcription Task
After submitting your transcription request, you'll want to monitor its progress and retrieve the results once processing completes. To do this:
1. Use the [`/transcribe/{task-id}`](poll-transcription-result) endpoint to check your task's status
2. Poll the status endpoint at reasonable intervals (we recommend 5-15 second intervals for most cases)
3. Once the status shows as `SUCCESS`, you can retrieve your full transcript
## Best Practices for Optimal Results
To get the most accurate transcriptions from our service:
1. **Use High-Quality Media**: Whenever possible, use media recorded in quiet environments with minimal background noise.
2. **Appropriate Media Format**: Submit uncompressed media formats like WAV or FLAC for best quality, or high-bitrate MP3s if file size is a concern.
3. **Speaker Clarity**: Encourage clear speaking with moderate pace for best recognition accuracy.
4. **Specify the Correct Language**: Always provide the correct language parameter to ensure our models apply the right language patterns.
5. **Segment Longer Content**: For very long recordings (over 2 hours), consider splitting into multiple smaller files for more efficient processing.
## Handling Common Issues
If you encounter problems with your transcription tasks, these troubleshooting steps may help:
### Rejected File Uploads
**Problem**: Your request returns an error about the file upload.
**Potential Solutions**:
* Verify your file is in one of our supported formats (`.mp3`, `.wav`, `.aac`, `.flac`, `.mp4`, `.mov`, `.mxf`)
* Check that your file isn't corrupted or empty
* Ensure your file doesn't exceed our size limit (20 MB)
### Incorrect Language Specification
**Problem**: Transcription results appear inaccurate or contain many errors.
**Potential Solutions**:
* Verify you specified the correct language code
* For multilingual content, choose the predominant language
## Taking Your Transcriptions Further
Once you've successfully transcribed your media content, consider these next steps:
1. **Semantic Analysis**: Extract key topics, sentiments, and entities from your transcribed text
2. **Content Indexing**: Make your media searchable by indexing the transcript content
3. **Accessibility Compliance**: Use transcripts to make your media content accessible to all users
4. **Translation**: Convert your transcript into other languages for global reach
5. **Summary Generation**: Create concise summaries of longer transcribed content
# Create Translated Story
Source: https://docs.camb.ai/api-reference/endpoint/create-translated-story
post /translated-story/{run_id}
Creates a translated story based on a previously generated story using the provided `run_id`
Expand your storytelling to global audiences with our comprehensive translation service. This powerful endpoint transforms your previously created stories into new languages, allowing your content to reach diverse linguistic communities. The system handles everything from translation to voice synthesis, delivering professional-quality results that preserve the original story's essence while adapting it naturally to the target language.
## The Translation Process
When you submit a story translation request, our system begins a sophisticated workflow:
Using your provided `run_id`, our system locates and retrieves your previously generated story, ensuring we're working with the complete content.
The story content is expertly translated to your target language using our proprietary translation engine, carefully preserving narrative flow, tone, and cultural nuances.
Our system selects appropriate voices for the target language that match the character of the original narration, then generates natural-sounding audio.
The translated story undergoes final checks to ensure audio quality, proper pacing, and narrative integrity in the new language.
Throughout this process, you can check on your task's progress using the [`/translated-story/{task_id}`](get-translated-story-status) endpoint with the `task_id` provided in your initial response.
## Language Selection
Choosing the right target language is essential for effective story translation. Our system supports over 148 languages, giving you incredible global reach. To specify your desired language:
1. Pass the locale tag (e.g. `"es-es"`, `"fr-fr"`) in your request. Numeric language IDs still work but are deprecated.
2. For the complete list of supported languages, query the [`/target-languages`](get-target-languages) endpoint.
This ensures our system correctly processes your content for the intended audience.
## Creating Your First Translated Story
Let's examine how to initiate a story translation task using Python:
```python [expandable] theme={null}
import requests
import json
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
# Define your translation request parameters
def translate_story(run_id, target_language):
"""
Submits a new story translation task and returns the task ID for tracking.
Parameters:
- run_id: The ID of the original story to translate
- target_language: Locale tag of the target language (e.g. "es-es"); numeric IDs still work but are deprecated
"""
try:
# Prepare the request body
payload = {
"target_language": target_language
}
# Submit the translation request
response = requests.post(
f"https://client.camb.ai/apis/translated-story/{run_id}",
headers=headers,
data=json.dumps(payload)
)
# Verify the request was successful
response.raise_for_status()
# Extract the task ID from the response
result = response.json()
task_id = result.get("task_id")
print(f"Story translation task submitted successfully! Task ID: {task_id}")
return task_id
except requests.exceptions.RequestException as e:
print(f"Error submitting story translation task: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
# Example usage
run_id = 12345 # Replace with your actual run_id
target_language = "es-es"
task_id = translate_story(run_id, target_language)
```
## Monitoring Your Translation Progress
After submission, your story enters our translation pipeline. You can monitor the progress by polling the status endpoint:
```python [expandable] theme={null}
def check_translation_status(task_id):
"""
Checks the status of a story translation task.
Returns the current status and any available result information.
Parameters:
- task_id: The ID of the translation task to check
"""
if not task_id:
print("No task ID provided.")
return None
try:
response = requests.get(
f"https://client.camb.ai/apis/translated-story/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Parse the status information
status_data = response.json()
print(f"Current status: {status_data['status']}")
# If the translation is complete, display the results
if status_data['status'] == "SUCCESS":
print("Story translation completed successfully!")
print(f"Translated story URL: {status_data.get('story_url')}")
return status_data
except requests.exceptions.RequestException as e:
print(f"Error checking translation status: {e}")
return None
# Check the status of your translation task
status_info = check_translation_status(task_id)
```
## Best Practices for Optimal Results
To achieve the best possible translations of your stories, consider these professional recommendations:
1. **Original Quality**: Ensure your source story is of high quality, as the translation will preserve any issues present in the original.
2. **Cultural Considerations**: Some stories may contain cultural references that don't translate directly. Consider this when selecting target languages.
3. **Language Pairing**: Some language pairs translate more smoothly than others. When possible, start with content that will translate well to your target language.
4. **Sequential Translation**: For best results, translate directly from the original language rather than creating "translations of translations."
5. **Test Translations**: Consider testing with shorter stories first to ensure the target language delivers the tone and style you're seeking.
## Practical Applications
Our story translation functionality enables exciting opportunities across various fields:
* **Global Education**: Make educational stories accessible to learners worldwide in their native languages.
* **Publishing**: Quickly expand your literary works to international markets without the traditional translation timeline.
* **Cultural Exchange**: Share folktales and cultural narratives across language barriers, fostering global understanding.
* **Language Learning**: Create parallel versions of stories for language learners to compare with original texts.
* **International Marketing**: Adapt brand stories and narratives for diverse global audiences.
By integrating this translation capability into your workflow, you can efficiently extend your storytelling reach across linguistic boundaries, dramatically reducing the time and resources traditionally required for multilingual content creation while maintaining impressive quality and authenticity.
# Create Translated Text-to-Speech
Source: https://docs.camb.ai/api-reference/endpoint/create-translated-tts
post /translated-tts
Creates a task to translate input text and generate corresponding speech audio
Transform written content across language barriers with our powerful translated text-to-speech system. This innovative endpoint enables you to seamlessly convert text from one language into spoken audio in another language in a single streamlined process. Whether you're creating multilingual content, developing educational materials, building accessible applications, or expanding your global reach, this capability allows you to quickly generate localized audio content while maintaining natural pronunciation and intonation specific to the target language.
Once the task is complete, the outputs can be retrieved using these endpoints:
* [`/translation-result/{run_id}`](get-translation-run-result): Returns the translated text.
* [`/tts-result/{run_id}`](get-tts-result): Returns the generated voiceover audio
## How It Works
When you submit a request to this endpoint, our system processes your input text through a streamlined workflow:
* First, the system creates a dedicated task and returns a unique `task_id` for tracking.
* Your source text is then accurately translated to the target language using advanced neural machine translation models that preserve meaning andn context.
* Finally, the translated text is converted into natural-sounding speech using language-specific voice models that capture the appropriate pronunciation and intonation of the target language.
* You can monitor the status of your request by polling the [`/translated-tts/{task_id}`](poll-translated-tts-result) endpoint until processing is complete.
## Creating Your First Translated Text-to-Speech Request
Let's examine how to initiate a translated text-to-speech task using Python:
```python [expandable] theme={null}
import requests
import json
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def create_translated_tts(text, source_language, target_language, voice_id=None):
"""
Submits a new translated text-to-speech task and returns the task ID for tracking.
Parameters:
- text: The source text to be translated and converted to speech
- source_language: Locale tag of the input text (e.g., "en-us"); numeric IDs (e.g. 1) still work but are deprecated
- target_language: Locale tag for the desired output (e.g., "es-es")
- voice_id: Optional specific voice to use for the target language
"""
try:
# Prepare the request body
payload = {
"text": text,
"source_language": source_language,
"target_language": target_language
}
# Add voice_id if specified
if voice_id:
payload["voice_id"] = voice_id
# Submit the request
response = requests.post(
"https://client.camb.ai/apis/translated-tts",
headers=headers,
data=json.dumps(payload)
)
# Verify the request was successful
response.raise_for_status()
# Extract the task ID from the response
result = response.json()
task_id = result.get("task_id")
run_id = result.get("run_id")
print(f"Translated TTS task submitted successfully! Task ID: {task_id}")
print(f"Run ID for retrieving results: {run_id}")
return task_id, run_id
except requests.exceptions.RequestException as e:
print(f"Error submitting translated TTS task: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None, None
# Example usage
source_text = "Welcome to our global product demonstration. We're excited to share these new features with you."
task_id, run_id = create_translated_tts(
text=source_text,
source_language="en-us", # Locale tag. Numeric IDs (e.g. 1) still work but are deprecated.
target_language="ja-jp"
)
```
## Monitoring Your Translation and Speech Generation Progress
After submission, your task enters our processing pipeline. You can monitor the progress by polling the status endpoint:
```python [expandable] theme={null}
def check_translated_tts_status(task_id):
"""
Checks the status of a translated text-to-speech task.
Returns the current status and any available result information.
Parameters:
- task_id: The ID of the task to check
"""
if not task_id:
print("No task ID provided.")
return None
try:
response = requests.get(
f"https://client.camb.ai/apis/translated-tts/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Parse the status information
status_data = response.json()
print(f"Current status: {status_data['status']}")
# If the task is complete, show how to access results
if status_data['status'] == "SUCCESS":
print("Translation and speech generation completed successfully!")
print(f"Use the run_id to retrieve your results.")
print(f"- Translation: GET /translation-result/{status_data.get('run_id')}")
print(f"- Audio: GET /tts-result/{status_data.get('run_id')}")
return status_data
except requests.exceptions.RequestException as e:
print(f"Error checking task status: {e}")
return None
# Check the status of your task
status_info = check_translated_tts_status(task_id)
```
## Retrieving Your Results
Once your task is complete, you can retrieve both the translated text and the generated audio using the provided run\_id:
```python [expandable] theme={null}
def get_translation_result(run_id):
"""
Retrieves the translated text result.
Parameters:
- run_id: The run ID returned from the initial request
"""
try:
response = requests.get(
f"https://client.camb.ai/apis/translation-result/{run_id}",
headers=headers
)
response.raise_for_status()
result = response.json()
print(f"Translation successful!")
print(f"Translated text: {result.get('translated_text')}")
return result
except requests.exceptions.RequestException as e:
print(f"Error retrieving translation: {e}")
return None
def get_tts_result(run_id):
"""
Retrieves the generated audio file.
Parameters:
- run_id: The run ID returned from the initial request
"""
try:
response = requests.get(
f"https://client.camb.ai/apis/tts-result/{run_id}",
headers=headers
)
response.raise_for_status()
result = response.json()
print(f"Audio retrieval successful!")
print(f"Audio URL: {result.get('audio_url')}")
return result
except requests.exceptions.RequestException as e:
print(f"Error retrieving audio: {e}")
return None
# Retrieve your results
translation = get_translation_result(run_id)
audio = get_tts_result(run_id)
```
## Best Practices for Translated Text-to-Speech
To achieve the highest quality results for your multilingual audio content:
1. **Provide Clear Source Text**: Ensure your source text is free of grammatical errors, unusual abbreviations, or ambiguous phrases to improve translation accuracy.
2. **Consider Cultural Context**: Be mindful of cultural references that may not translate effectively across languages, and adapt your content accordingly.
3. **Use Appropriate Sentence Length**: For optimal speech generation, break long, complex sentences into shorter ones, especially for languages that differ structurally from the source.
## Supported Languages & Voices
Our system supports a wide range of language pairs for translation and speech synthesis. The quality and naturalness of speech may vary depending on the specific language combinations. Checkout the [`/target-languages`](get-target-languages) endpoint for a list of supported languages and [`/list-voices`](list-voices) endpoint for a list of available voices which includes public voices and your own custom voices.
# Create Translation
Source: https://docs.camb.ai/api-reference/endpoint/create-translation
post /translate
Translate text into multiple languages with customizable settings for formality, gender, and specialized vocabulary to meet your global communication needs.
This endpoint transforms your source text into fluent, natural-sounding translations in your target language, enabling seamless multilingual communication for your applications. When you provide text along with language preferences and customization options, our system initiates a translation task and returns a unique identifier you can use to track its progress.
## Customizing Your Translation
### Language Selection
For successful translation, you'll need to specify both source and target languages:
* **Source Language**: The original language of your text
* **Target Language**: The language you want your text translated into
To see what's available:
* Check the [`/source-languages`](get-source-languages) or [`/target-languages`](get-target-languages) endpoints for a complete list of supported languages with their corresponding IDs.
### Style and Tone Customization
Our platform offers several ways to tailor translations to your specific audience:
* **Formality**: Adjust the formality level to match your context:
* Formal (1): Professional communications, official documents
* Informal (2): Casual conversations, social media content
* **Gender**: Specify grammatical gender preferences when relevant in the target language
* **Age**: Adjust vocabulary and expressions to be age-appropriate for your intended audience
### Domain Expertise
For specialized content, you can enhance accuracy with domain-specific terminology:
* **Chosen Dictionaries**: Include specialized vocabulary dictionaries to ensure technical terms are translated appropriately for fields like medicine, law, technology, or other industries
## How the Process Works
This endpoint uses an asynchronous workflow, allowing your application to continue operations while translation processing happens in the background:
Send your text array along with language and customization preferences. You can translate multiple text segments in a single request, which is ideal for processing larger documents or batches of content.
Once your request is submitted, the system immediately returns a unique `task_id`. This identifier lets you check on your translation's progress at any time.
Use your `task_id` to monitor the current status of your request by calling the [`/translate/{task_id}`](poll-translation-result) endpoint. This will tell you whether your translation is still in progress, completed, or if any issues occurred.
This asynchronous approach is particularly effective for handling longer texts or processing multiple translations simultaneously without blocking your application's workflow.
## Example: Creating Your First Translation
Here's a practical example showing how to translate business communications from English to Spanish:
```python [expandable] theme={null}
import requests
import time
# Define the translation request
translation_payload = {
"source_language": "en-us", # Locale tag. Numeric IDs (e.g. 1) still work but are deprecated.
"target_language": "es-es",
"texts": [
"Thank you for your inquiry about our services.",
"We would be happy to schedule a meeting next week to discuss your needs in detail.",
"Please let us know what day works best for you."
],
"formality": 1, # Formal tone
"gender": 1, # Male grammatical forms when applicable
"age": 30 # Adult-appropriate language
}
# Set up your API credentials
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
# Step 1: Submit your translation request
response = requests.post(
"https://client.camb.ai/apis/translate",
json=translation_payload,
headers=headers
)
# Check if the request was successful
response.raise_for_status()
task_data = response.json()
task_id = task_data["task_id"]
print(f"Translation task created! Task ID: {task_id}")
# Step 2: Check progress until complete
while True:
status_response = requests.get(
f"https://client.camb.ai/apis/translate/{task_id}",
headers=headers
)
status_data = status_response.json()
status = status_data["status"]
print(f"Status: {status}")
if status == "SUCCESS":
run_id = status_data["run_id"]
break
elif status == "ERROR":
print("Translation task failed!")
break
# Wait before checking again
time.sleep(2)
# Step 3: Process your translated text
if status == "SUCCESS":
print("✨ Translation complete!")
print(f"Use the `run_id` {task_data.get('run_id')} to fetch your translation.")
```
With this approach, you can efficiently translate content across languages while maintaining appropriate tone, formality, and specialized terminology to ensure your message resonates with its intended audience.
# Create Translation Stream
Source: https://docs.camb.ai/api-reference/endpoint/create-translation-stream
post /translation/stream
Deprecated: Convert text between languages in real-time with contextual adaptations, delivering translated content as it's generated for immediate use in conversational interfaces and live applications.
This endpoint is deprecated. For new integrations, use the standard translation task flow with [`POST /translation`](create-translation), then poll task status and fetch the completed result.
This endpoint provides instantaneous text translation with adaptive context handling, streaming results character-by-character as they're processed. This approach enables real-time subtitling, live chat translation, and dynamic content localization without waiting for full document processing.
## Customizing Your translation
### Contextual Adaptation Parameters
Enhance your translations with linguistic context controls:
* **Formality Level** (Optional):
| Setting | Value | Use Case |
| :------ | :---- | :----------------------------------------------------------- |
| Formal | 1 | Business documents, academic papers, official correspondence |
| Casual | 2 | Chat messages, social media, casual communication |
* **Grammatical Gender** (Optional):
*Applies to languages with gender-specific grammar*
| Setting | Value |
| :------------ | :---- |
| Not Specified | 0 |
| Male | 1 |
| Female | 2 |
| Neutral | 9 |
### Language Support
* Configure your translation pipeline using:
* [`/source-languages`](get-source-languages) - Supported input languages
* [`/target-languages`](get-target-langauages) - Available output languages
## Implementation Guide
Streaming Translation Workflow:
```python Streaming using Sync Python [expandable] theme={null}
import requests
translation_config = {
"text": "Jupiter, the largest planet in our solar system...",
"source_language": "en-us", # Locale tag. Numeric IDs (e.g. 1) still work but are deprecated.
"target_language": "hi-in",
"formality": 2, # Formal
"gender": 1 # Male grammatical gender
}
def sync_translation_stream(config):
"""Handle translation stream synchronously"""
headers = {"x-api-key": "your_api_key_here"}
with requests.post(
"https://client.camb.ai/apis/translation/stream",
json=config,
headers=headers,
stream=True
) as response:
# Verify successful connection
response.raise_for_status()
# Display credit cost
print(f"Credits required: {response.headers.get('X-Credits-Required', 'Unknown')}")
# Process stream chunks
full_translation = ""
for chunk in response.iter_content(chunk_size=128):
try:
decoded = chunk.decode('utf-8')
full_translation += decoded
print(decoded, end='', flush=True)
except UnicodeDecodeError:
print("�", end='') # Error placeholder
return full_translation
# Execute the translation
translated_text = sync_translation_stream(translation_config)
print("\nComplete Translation:\n", translated_text)
```
```python Streaming using Async Python [expandable] theme={null}
import aiohttp
import asyncio
translation_config = {
"text": "Jupiter, the largest planet in our solar system...",
"source_language": "en-us", # Locale tag. Numeric IDs (e.g. 1) still work but are deprecated.
"target_language": "hi-in",
"formality": 2, # Formal translation
"gender": 1 # Male grammatical gender
}
async def stream_translation(session, config):
"""Process real-time translation stream"""
async with session.post(
"https://client.camb.ai/apis/translation/stream",
json=config,
headers={"x-api-key": "your_api_key_here"}
) as response:
# Verify successful stream initiation
if response.status != 200:
print(f"Error: {await response.text()}")
return ""
# Process stream chunks
full_translation = ""
async for chunk in response.content.iter_any():
try:
decoded_chunk = chunk.decode('utf-8')
full_translation += decoded_chunk
print(decoded_chunk, end='', flush=True)
except UnicodeDecodeError:
print("�", end='') # Error placeholder
return full_translation
async def main():
async with aiohttp.ClientSession() as session:
translated = await stream_translation(session, translation_config)
print("\nFinal Translation:\n", translated)
asyncio.run(main())
```
**When to use synchronous vs asynchronous:**
* Use synchronous (`requests`) for:
* Simple scripts
* Low-concurrency applications
* Quick prototyping
* Use asynchronous (`aiohttp`) for:
* High-performance applications
* Parallel translation streams
* Web servers with async frameworks
## Response Handling
* **Stream Format**: UTF-8 encoded text/event-stream with incremental translations.
* **Credit Tracking**: `X-Credits-Required` header shows computational resources used.
* **Error Handling**: Failed streams immediately terminate with error message.
## Use Case Examples
* **Live Caption Translation**: Convert spoken language subtitles in real-time
* **Chat Localization**: Instant message translation for multilingual support teams
* **Document Preview**: Stream translated content while full processing continues
This streaming solution is ideal for applications requiring immediate partial results while maintaining full translation context awareness. The character-level streaming allows for dynamic UI updates and progressive content rendering.
# Create Text-to-Speech
Source: https://docs.camb.ai/api-reference/endpoint/create-tts
post /tts
Deprecated: Convert text to natural-sounding speech with customizable voice settings, allowing you to generate audio files for playback in your applications.
The asynchronous `POST /tts` flow is deprecated. If you’re starting a new integration, use `POST /tts-stream` instead—you receive audio as it’s generated, without juggling task status, run IDs, and separate download calls.
This endpoint transforms your written text into remarkably natural speech, opening up possibilities for narration, accessibility features, and interactive experiences in your applications. When you provide text along with voice preferences, our Model creates an audio file that captures the nuances and natural flow of human speech.
## Personalizing Your Voice
### Voice Personalization Options
You can shape the character of your generated voice by specifying these key attributes:
* **Gender**: Select the voice gender with a simple numeric code:
* **Age**: Add in the voice age to reflect the intended audience or context.
### Selecting Your Voice
Our platform offers two approaches to finding the perfect voice:
* **Choose from our voice library:** Browse our collection of ready-to-use voices through the [`/list-voices`](list-voices) endpoint to find the perfect match for your project.
* **Use your signature voice:** Utilize the [`/create-custom-voice`](create-custom-voice) endpoint to clone an audio recording containing your signature voice.
### Language Support
Our technology supports numerous languages and dialects for global reach. To see what's available:
* Check the [`/source-languages`](get-source-languages) or [`/target-languages`](get-target-languages) endpoints for a complete list of supported languages with their corresponding IDs.
## How the Process Works
This endpoint uses an asynchronous workflow, which means your application can keep doing other things while the speech is being generated. Here's how it works, step-by-step:
Start by sending in your text, along with voice preferences such as language, age, and gender. You can also specify a voice from our library or a custom voice you've created.
Once your request is received, our system instantly returns a unique `task_id`. This lets you check back later to see how things are going—just like tracking a package.
Use your `task_id` to check the current status of your request by calling the [`/tts/{task_id}`](get-tts-result) endpoint. You’ll know whether your audio is still being generated, completed, or if something went wrong.
When your task is marked as complete (`SUCCESS`), you'll get a `run_id`. Use this ID to download your final audio file from the [`/tts-result/{run_id}`](get-tts-result) endpoint.
This approach works particularly well for longer passages or when processing multiple requests simultaneously.
## Example: Creating Your First Audio
Here's a practical example showing how to generate speech about Mars:
```python [expandable] theme={null}
import requests
import time
# Define the text and voice characteristics
tts_payload = {
"text": "Mars, the red planet, captivates our imagination with its rusty landscape, ancient river valleys, and massive polar ice caps. Its thin atmosphere whispers of a warmer, wetter past that scientists are eager to understand.",
"voice_id": 147320, # Replace with your chosen voice ID
"language": "en-us", # Locale tag. Numeric IDs (e.g. 1) still work but are deprecated.
"gender": 1, # Male voice
"age": 30 # Adult voice characteristic
}
# Set up your API credentials
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
# Step 1: Submit your text-to-speech request
response = requests.post(
"https://client.camb.ai/apis/tts",
json=tts_payload,
headers=headers
)
# Check if the request was successful
response.raise_for_status()
task_data = response.json()
task_id = task_data["task_id"]
print(f"Speech task created! Task ID: {task_id}")
# Step 2: Check progress until complete
while True:
status_response = requests.get(
f"https://client.camb.ai/apis/tts/{task_id}",
headers=headers
)
status_data = status_response.json()
status = status_data["status"]
print(f"Status: {status}")
if status == "SUCCESS":
run_id = status_data["run_id"]
break
elif status == "FAILED":
print("Task failed!")
break
# Wait before checking again
time.sleep(2)
# Step 3: Download your audio file
if status == "SUCCESS":
print(f"Speech ready! Run ID: {run_id}")
audio_response = requests.get(
f"https://client.camb.ai/apis/tts-result/{run_id}",
headers=headers,
stream=True
)
# Save the audio file
with open("speech.wav", "wb") as audio_file:
for chunk in audio_response.iter_content(chunk_size=1024):
if chunk:
audio_file.write(chunk)
print("✨ Generated speech was saved as 'speech.wav'")
```
With this approach, you can create engaging audio content that brings your text to life while your application continues performing other tasks during processing.
# Stream Text-to-Speech Audio
Source: https://docs.camb.ai/api-reference/endpoint/create-tts-stream
post /tts-stream
Convert text to speech in real-time with customizable voice characteristics, delivering audio content as it's generated for immediate playback in your applications.
[Camb AI Python SDK Examples](https://github.com/camb-ai/cambai-python-sdk/tree/main/examples/async_tts_call.py)
[Link To Detailed Models Overview](/models)
## How the Streaming Process Works
Our streaming service is designed for simplicity and speed. Here’s how it works from request to playback:
Send a POST request containing your text and desired audio configuration, including the voice, language, and output format.
The server immediately begins processing and sends audio data back in chunks over the same connection. Your application can start playing the audio as soon as the first chunk arrives.
Continue reading the byte stream until the connection closes, which signals the end of the audio. You can also monitor real-time usage via the `X-Credits-Required` header included in the response.
### Language Support
The `language` field takes a **BCP-47 locale code** (e.g. `en-us`, `hi-in`, `zh-cn`). It controls the accent and pronunciation of the generated speech — the model does **not** translate the input text, so the text you supply should already be written in the target language.
#### Coverage by model
| Speech model | Locales supported |
| :----------------------------------------- | :---------------- |
| `mars-flash`, `mars-pro` | 33 |
| `mars-8.1-flash-beta`, `mars-8.1-pro-beta` | 312 |
| `mars-instruct` | 142 |
See the full per-model locale list in [Language Support](/language-support).
Haryanvi (`bgc-in`) and Bhojpuri (`bho-in`) are supported only by
`mars-instruct`. Set `speech_model` explicitly to `mars-instruct` when using
either locale; the endpoint otherwise defaults to `mars-pro`, which rejects
them with HTTP 422.
#### Choosing a locale
* Use the most specific regional variant available for the accent you want. For example, prefer `es-mx` over `es-es` for a Mexican Spanish accent, or `zh-cn-sichuan` over `zh-cn` for a Sichuan-flavored Mandarin.
* For best results on the MARS 8.1 beta models, supply a **reference voice in the same language and accent** as the target locale.
* Codes are case-sensitive lowercase (e.g. `pt-br`, not `pt-BR`).
#### Validation behavior
If the requested `language` is not supported by the selected `speech_model`, the API responds with **HTTP 422** and a `ValidationError` body that lists the allowed locales for that model. Example:
```json theme={null}
{
"detail": [{
"loc": ["body"],
"msg": "Value error, Language 'zh-tw' is not supported for speech model 'mars-flash'. Allowed languages are: ['en-us', 'en-in', 'zh-cn', ...]"
}]
}
```
### Advanced Customization
Fine-tune the audio with additional parameters to control the performance, style, and quality of the generated speech. These are sent in the same JSON payload.
* **`speech_model`**: Specify the model for synthesis. Available values include `mars-8.1-flash-beta`, `mars-8.1-pro-beta`, `mars-flash`, `mars-pro`, and `mars-instruct`.
* **`user_instructions`**: Guide the voice's overall delivery (e.g., "Warm, clear, and conversational"). Only send this when `speech_model` is `mars-instruct`.
* **Expressive text tags**: With `mars-instruct`, you can also embed delivery tags directly in the `text` field (for example, emotion tags or SSML-style pauses) to shape pacing and tone around specific lines.
* **`output_configuration`**: Set the audio format (`wav`, `mp3`), sample rate, and toggle output enhancement.
* `apply_enhancement` (boolean, optional): Applies output audio enhancement (loudness, denoising, polish). Defaults to `true` for most models, `false` for the speed-oriented `mars-flash` and `mars-8.1-flash-beta` models. Set explicitly to override.
* **`voice_settings`**: Enhance reference audio quality, maintain the source accent, or adjust the speaking rate.
* **`inference_options`**: Adjust stability, temperature, and speaker similarity for unique results.
`user_instructions` is only supported when `speech_model` is set to `mars-instruct`.
The `mars-8.1-flash-beta` and `mars-8.1-pro-beta` models do not support the following parameters:
* `acoustic_quality_boost`
* `temperature`
* `speaker_similarity`
* `maintain_source_accent`
* `stability`
* `output_enhancement`
* `enhance_named_entities_pronunciation`
* `localize_speaker_weight`
### MARS 8.1 Beta Text Controls
The `mars-8.1-flash-beta` and `mars-8.1-pro-beta` models support inline controls for English pronunciation and expressive non-verbal sounds. Add these controls directly in the `text` field.
#### Pronunciation Control (English)
Use CMU pronunciation dictionary phonemes in uppercase, wrapped in brackets, to override default English pronunciations.
```python theme={null}
payload = {
"text": "He plays the [B EY1 S] guitar while catching a [B AE1 S] fish.",
"language": "en-us",
"voice_id": 147320,
"speech_model": "mars-8.1-flash-beta"
}
```
#### Non-verbal Symbols
Insert supported tags directly in the text to add expressive non-verbal sounds.
```python theme={null}
payload = {
"text": "[laughter] You really got me. I didn't see that coming at all.",
"language": "en-us",
"voice_id": 147320,
"speech_model": "mars-8.1-flash-beta"
}
```
Supported tags: `[laughter]`, `[sigh]`, `[confirmation]`, `[question]`, `[surprise]`, `[dissatisfaction]`.
### Expressive Text Tags (`mars-instruct`)
You can directly convey expression in the input text by adding short tags for delivery. For a deeper guide to emotion tag intensity, see the [Emotion Tag Gradation Guide](/tutorials/emotional-voice-control#emotion-tag-gradation-guide).
* `[speaking slowly] You need to understand this. It is very important. We should do this the right way.`
* `[angry] You need to understand this! It is very important, we should do this the right way!`
* `[gentle, reassuring] Take a deep breath. You're doing well. Let's go step by step.`
* `Please pause here then continue in a calm, clear tone.`
Keep tags short and place them near the sentence you want to influence.
For comprehensive examples and best practices, see the [Emotional Voice Control tutorial](/tutorials/emotional-voice-control).
### Tips For Best Results:
* For texts with numbers expand the numbers to words. For example, instead of "123" to "one hundred twenty three" or "one two three" as you need.
* For code-switched sentences, perform transliteration to convert the text to your chosen TTS language.
Both of above could be done by a small LLM.
* To adjust pacing or approximate length, use `voice_settings.speaking_rate`. The streaming TTS endpoint does not support a duration parameter.
### Output format support by model
Supported `output_configuration.format` values depend on the selected `speech_model`:
| Speech Model | Supported output formats |
| :-------------------- | :--------------------------------------------------------------------------------------------------------- |
| `mars-8.1-flash-beta` | `wav`, `mp3`, `flac`, `adts`, `pcm_s16le`, `pcm_s16be`, `pcm_s32be`, `pcm_s32le`, `pcm_f32le`, `pcm_f32be` |
| `mars-8.1-pro-beta` | `wav`, `mp3`, `flac`, `adts`, `pcm_s16le`, `pcm_s16be`, `pcm_s32be`, `pcm_s32le`, `pcm_f32le`, `pcm_f32be` |
| `mars-flash` | `wav`, `mp3`, `flac`, `adts`, `pcm_s16le`, `pcm_s16be`, `pcm_s32be`, `pcm_s32le`, `pcm_f32le`, `pcm_f32be` |
| `mars-pro` | `wav`, `mp3`, `flac`, `adts`, `pcm_s16le`, `pcm_s16be`, `pcm_s32be`, `pcm_s32le`, `pcm_f32le`, `pcm_f32be` |
| `mars-instruct` | `wav`, `flac`, `adts`, `pcm_s16le`, `pcm_s32be`, `pcm_s32le`, `pcm_f32le`, `pcm_f32be` |
## Example: Real-time Audio Streaming
This example shows how to call the endpoint and save the incoming audio stream to a file.
```python [expandable] theme={null}
import requests
payload = {
"text": "Jupiter, the largest planet in our solar system, is a gas giant with swirling storms like the iconic Great Red Spot.",
"language": "en-us",
"voice_id": 147320,
"speech_model": "mars-instruct",
"user_instructions": "Warm, clear, and conversational.",
"enhance_named_entities_pronunciation": True,
"output_configuration": {
"format": "wav"
},
"voice_settings": {
"enhance_reference_audio_quality": False,
"maintain_source_accent": False,
"speaking_rate": 1.0
},
"inference_options": {
"inference_steps": 60,
}
}
headers = {
"x-api-key": "your-api-key"
}
response = requests.post(
"https://client.camb.ai/apis/tts-stream",
json=payload,
headers=headers,
stream=True
)
response.raise_for_status()
with open("output.wav", "wb") as audio_file:
for chunk in response.iter_content(chunk_size=1024):
if chunk:
audio_file.write(chunk)
print("✨ Stream complete. Audio saved to output.wav")
```
## SDK Example: Async Streaming
```python theme={null}
import asyncio
from camb.client import AsyncCambAI, save_async_stream_to_file
from camb.types.stream_tts_output_configuration import StreamTtsOutputConfiguration
from camb.types.stream_tts_voice_settings import StreamTtsVoiceSettings
# Initialize the async client
client = AsyncCambAI(api_key="your-api-key")
async def main():
# Stream the TTS generation
response = client.text_to_speech.tts(
text="Experience high quality realistic sounds with Camb AI.",
language="en-us",
speech_model="mars-8.1-flash-beta",
voice_id=,
voice_settings=StreamTtsVoiceSettings(
speaking_rate=1.0
),
output_configuration=StreamTtsOutputConfiguration(
format="wav"
)
)
# Save the stream to a file (or process chunks as they arrive)
await save_async_stream_to_file(response, "async_stream_output.wav")
print("Audio stream saved to async_stream_output.wav")
if __name__ == "__main__":
asyncio.run(main())
```
## Streaming vs. Asynchronous: Which to Choose?
Select the right tool for your job by understanding the key differences between our TTS endpoints.
Ideal for real-time, interactive experiences where immediate audio feedback is crucial.
Perfect for non-real-time tasks, long-form content, or when you need to retrieve a complete audio file later.
# Delete a Dictionary
Source: https://docs.camb.ai/api-reference/endpoint/delete-dictionary
delete /dictionaries/{dictionary_id}
Permanently removes a dictionary and all its associated terms and translations from the system. This irreversible action completely eliminates the dictionary's data and cannot be undone.
## Overview
Deleting a dictionary represents one of the most consequential operations you can perform in a dictionary management system. Unlike updating or retrieving information, deletion is permanent and irreversible, making it essential to understand both the technical mechanics and the broader implications of this action before implementing it in your applications.
When you delete a dictionary, you're not simply removing a reference or hiding the content from view. Instead, you're instructing the system to completely eliminate the dictionary and everything it contains from the database. This includes not only the dictionary's identifying information and metadata, but also every single term-translation pair that was stored within it.
## Understanding the Permanence of Deletion
The irreversible nature of dictionary deletion serves important purposes in data management, but it also creates significant responsibilities for developers and users. From a system perspective, permanent deletion helps maintain database efficiency by truly removing unused data rather than simply marking it as inactive. This approach prevents the accumulation of obsolete records that could slow down queries and consume storage space unnecessarily.
However, this permanence also means that any applications, workflows, or users that depend on the deleted dictionary will immediately lose access to that data. References to the dictionary will become invalid, translation lookups will fail, and any cached content based on that dictionary may become inconsistent with the system state. Understanding these cascading effects helps you design better error handling and user communication around deletion operations.
# Delete a Term in Dictionary
Source: https://docs.camb.ai/api-reference/endpoint/delete-term-in-dictionary
delete /dictionaries/term/{dictionary_id}/{term_id}
Permanently removes a specific term and all its associated translations from a dictionary, providing precise control over dictionary content while maintaining the integrity of remaining terms.
Deleting individual terms from dictionaries represents a fundamentally different operation from deleting entire dictionaries, though both share the characteristic of permanent data removal. When you delete a term, you're performing linguistic surgery - carefully removing specific content while preserving the broader dictionary structure and all other terms that users and applications depend upon.
## The Architecture of Precise Removal
The endpoint's design emphasizes surgical precision through its dual-parameter approach, requiring you to specify both the dictionary context and the exact term to be removed. This two-level targeting system prevents the kind of broad, accidental deletions that could damage valuable linguistic resources while ensuring that removal operations affect exactly the content you intend to eliminate.
## The Permanence Factor in Term Deletion
Like dictionary deletion, term deletion is permanent and irreversible, but the scope of impact differs significantly. When you delete a term, you're removing not just the source language entry, but all associated translations, usage examples, metadata, and any other linguistic information connected to that term concept. This comprehensive removal ensures that no orphaned data remains in the system, but it also means that recovery requires rebuilding the entire term entry from scratch.
## Quality Considerations in Term Removal
Consider how term deletion might affect users who have grown accustomed to finding specific terminology in your dictionary. Applications that cache dictionary content might need updates to reflect the removal, and any bookmarks or saved references to the deleted term will become invalid. Understanding these downstream effects helps you plan term deletion operations as part of broader dictionary maintenance strategies rather than isolated removal actions.
# Delete a Voice
Source: https://docs.camb.ai/api-reference/endpoint/delete-voice
delete /delete-voice/{voice_id}
Permanently deletes a custom voice from your workspace using its voice ID.
## Overview
Use this endpoint to remove a custom voice you no longer need. You can delete only voices you created, and you must use an API key from the workspace that owns the voice.
This is a permanent action, so make sure the voice is not used by any active workflows before deleting it.
## Path Parameter
* `voice_id`: The numeric ID of the voice to delete (for example, `9013`).
## Example Request
```bash theme={null}
curl -X DELETE "https://client.camb.ai/apis/delete-voice/9013" \
-H "x-api-key: YOUR_API_KEY"
```
## Example Response
```json theme={null}
{
"status": "ok"
}
```
# End to End Dubbing
Source: https://docs.camb.ai/api-reference/endpoint/end-to-end-dubbing
post /dub
Initiate a full end to end dubbing task.
Transform your media content for global audiences with our comprehensive dubbing solution. This powerful endpoint automates the entire dubbing process, taking your original media and producing a version that speaks naturally in your target language. The system handles everything from transcription to voice synthesis, delivering professional-quality results without requiring specialized audio engineering knowledge.
## The Dubbing Process
When you submit a dubbing request, our system begins a multi-stage workflow:
Our intelligent system works its magic behind the scenes to prepare your content for flawless localization.
The transcribed text is expertly translated to your target language using our proprietary translation engine [BOLI](https://www.camb.ai/#Research).
Voiceovers are created using natural-sounding synthetic voices using our in-house novel speech model [MARS](https://www.camb.ai/#Research).
Everything is combined into a seamless final product.
Throughout this process, you can check on your task's progress using the [`/dub/{task_id}`](get-end-to-end-dubbing-status) endpoint with the `task_id` provided in your initial response.
## Compatible Media Sources
Our dubbing service accommodates various media sources to fit your workflow needs. The `video_url` parameter in your request can point to any of the following:
### Online Platforms
Use content directly from popular content platforms:
* **YouTube videos**: Simply provide the standard YouTube video URL.
* **Google Drive**: Link to media files stored in Google Drive (ensure they're publicly accessible).
* **Direct URLs**: Any direct link to a media file that doesn't require authentication.
### Supported File Formats
Our system processes a wide range of professional and consumer media formats:
| Media Type | Supported Formats |
| :---------- | :------------------ |
| Video Files | MP4, MOV, MXF |
| Audio Files | MP3, FLAC, WAV, AAC |
This flexibility allows you to work with both broadcast-quality content and consumer-grade media without conversion hassles.
Please note that MXF format support is exclusively available to customers on our Enterprise plan, offering professional broadcast-quality media handling for organizations with advanced needs.
## Language Configuration
Specifying the right languages is crucial for successful dubbing. Your request needs to include:
* **Source Language**: The original language spoken in your media.
* **Target Language(s)**: The language(s) you want your content to be dubbed into.
Both parameters require specific language identifiers from our system. To find the correct IDs:
1. Query the [`/source-languages`](get-source-languages) endpoint for available source language options.
2. Check the [`/target-languages`](get-target-languages) endpoint for supported target languages.
Using these official IDs ensures our system correctly processes your content.
## Transcription Mode
The optional `transcription_mode` request field controls the transcription pass used before dubbing:
* **`fast`** (default): returns a transcript more quickly while maintaining quality.
* **`slow`**: takes longer and may produce a more accurate transcript through a more thorough pass.
Omit the field to use `fast`.
## Keeping Music in the Foreground
The optional `include_music_in_fg` parameter controls how background music is handled during source separation:
* **`true`** (default): music is preserved in the foreground audio alongside speech.
* **`false`**: music is stripped out of the foreground, isolating speech.
Omit the parameter to keep the default behaviour of retaining music.
## Creating Your First Dubbing request
Let's look at how to initiate a dubbing task with Python:
```python [expandable] theme={null}
import requests
import json
import time
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
# Define your dubbing request parameters
dubbing_request = {
"video_url": "https://www.youtube.com/watch?v=exampleVideo", # Your media URL
"source_language": "en-us", # Locale tag. Numeric IDs (e.g. 1) still work but are deprecated.
"target_languages": ["es-es"],
"transcription_mode": "fast",
"include_music_in_fg": True, # keep music in the foreground audio (default); set False to strip it
}
# Submit the dubbing request
def submit_dubbing_task(payload):
"""
Submits a new dubbing task and returns the task ID for tracking.
"""
try:
response = requests.post(
"https://client.camb.ai/apis/dub",
headers=headers,
data=json.dumps(payload)
)
# Verify the request was successful
response.raise_for_status()
# Extract the task ID from the response
result = response.json()
task_id = result.get("task_id")
print(f"Dubbing task submitted successfully! Task ID: {task_id}")
return task_id
except requests.exceptions.RequestException as e:
print(f"Error submitting dubbing task: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
# Call the function to submit your dubbing task
task_id = submit_dubbing_task(dubbing_request)
```
## Monitoring Your Dubbing Progress
After submission, your content enters our processing pipeline. The time required depends on the length and complexity of your media. You can check progress by polling the status endpoint:
```python [expandable] theme={null}
def check_dubbing_status(task_id):
"""
Checks the status of a dubbing task.
Returns the current status and any available result information.
"""
if not task_id:
print("No task ID provided.")
return None
try:
response = requests.get(
f"https://client.camb.ai/apis/dub/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Parse the status information
status_data = response.json()
print(f"Current status: {status_data['status']}")
return status_data
except requests.exceptions.RequestException as e:
print(f"Error checking dubbing status: {e}")
return None
# Check the status of your task
status_info = check_dubbing_status(task_id)
```
## Use Your Own Transcript or Translation
You can include SRT file contents directly in the JSON body of `POST /dub`:
* `source_transcript`: an optional transcript in `source_language`.
* `target_transcripts`: optional translations, each with a `language` matching one
of your requested target languages. Supply at most one SRT per language.
Each script takes `content` containing the SRT text and an optional `format`, whose
only supported value is `srt`. Read the file as UTF-8; do not send a filename, URL,
base64 string, multipart upload, or an array of segments.
```python theme={null}
from pathlib import Path
import requests
payload = {
"video_url": "https://example.com/video.mp4",
"source_language": "en-us",
"target_languages": ["es-es", "fr-fr"],
"source_transcript": {
"format": "srt",
"content": Path("original.srt").read_text(encoding="utf-8"),
},
"target_transcripts": [
{
"language": "es-es",
"format": "srt",
"content": Path("spanish.srt").read_text(encoding="utf-8"),
}
],
}
response = requests.post(
"https://client.camb.ai/apis/dub",
headers={"x-api-key": "your-api-key"},
json=payload,
timeout=60,
)
response.raise_for_status()
task_id = response.json()["task_id"]
```
This example supplies the original transcript and Spanish translation; French is
translated automatically. You can also send only `source_transcript`, only
`target_transcripts`, or neither. If you have the original transcript, include it
alongside your translations to provide source-language context. Requests without
these fields retain the existing automatic workflow. The task ID, polling, and
result endpoints are unchanged.
The API stores supplied scripts as temporary `.srt` objects under `temp/` in your
workspace's configured storage before passing them to the dubbing pipeline.
An SRT `content` string looks like this in JSON:
```json theme={null}
{
"format": "srt",
"content": "1\n00:00:00,500 --> 00:00:02,800\nWelcome back.\n"
}
```
### Validation and limits
* Maximum **2 MiB of UTF-8 text per script**; **10 MiB combined**
across the original and translations, with at most 100 target scripts.
* Scripts must contain at least one cue parseable by the `srt` library.
Standard SRT uses `HH:MM:SS,mmm --> HH:MM:SS,mmm` and blank lines between cues.
Parsing uses the `srt` library with parse errors enabled; its supported
variations, including dot-separated milliseconds, are also accepted.
* Overlapping and out-of-order cues are accepted. No additional cue-count,
numbering, timing, control-character, or dialogue-content checks are imposed
beyond the parser. UTF-8 BOM and Windows/Mac line endings are normalized.
* Target scripts must use supported languages selected in `target_languages`
(or the legacy `target_language`). Language aliases are normalized before
checking for duplicates. Unknown properties inside a script are rejected.
Invalid scripts return **HTTP 422** before script storage or dubbing submission.
Errors identify the input field. Unparseable SRT returns
`SRT content could not be parsed; check cue numbers and timestamps`.
Use timestamps relative to the original media and scripts that match that media.
Request validation checks SRT structure; it does not download the media to check
its duration or verify the language of your text. Supplied scripts use the existing
dubbing pipeline's timing and speech processing; this option does not introduce
an exact-wording or exact-timing output mode.
## Best Practices for Optimal Results
To get the most from our dubbing service, consider these professional tips:
1. **Source Quality Matters**: Higher quality original media yields better dubbing results.
2. **Language Selection**: Choose the right language for your audience to ensure clarity and authenticity.
## Practical Applications
Our end-to-end dubbing functionality opens exciting possibilities across industries:
* **E-Learning**: Make educational content accessible to global learners.
* **Marketing**: Localize promotional videos for international markets.
* **Entertainment**: Bring films and shows to new language audiences.
* **Corporate Communications**: Ensure company messages reach multilingual teams.
* **Social Media**: Expand your content's reach across language barriers.
By integrating this API into your workflow, you can dramatically reduce the time and expense traditionally associated with professional dubbing while maintaining impressive quality.
# Get Audio Separation Run Results (Bulk)
Source: https://docs.camb.ai/api-reference/endpoint/fetch-audio-separation-run-info-results
post /audio-separation-results
Retrieve separated audio components for multiple completed Audio Separation tasks using multiple run IDs.
# Accessing Multiple Separated Audio Collections
This endpoint enables you to retrieve the results from multiple completed audio separation tasks in a single, efficient request. Instead of making individual requests for each audio separation result, you can fetch foreground and background audio components from several processing runs simultaneously, streamlining your workflow when dealing with batch audio operations.
Each audio separation task produces two distinct audio tracks from your original recording: a **foreground** track containing primary audio elements (speech, vocals, or main instruments) and a **background** track with supporting elements (ambient sounds, musical accompaniment, or secondary audio). This bulk endpoint allows you to collect these separated components from multiple runs at once, making it ideal for applications processing audio libraries, podcast batches, or large-scale content analysis projects.
## How Bulk Audio Separation Retrieval Works
The bulk retrieval system operates on a simple principle: you provide an array of run IDs corresponding to your completed audio separation tasks, and the system returns organized results for each requested separation. This approach offers significant advantages over individual retrieval requests:
**Efficiency Benefits:**
* Reduces network overhead by consolidating multiple requests into one
* Minimizes latency when retrieving results from several audio separation tasks
* Simplifies client-side code for handling multiple audio file collections
* Provides better performance for batch audio processing workflows
**Practical Applications:**
* Processing results from multiple podcast episodes or music tracks
* Building audio libraries with separated components
* Batch operations for content creators working with multiple recordings
* Automated workflows that separate audio from video content in bulk
## Request Format
The endpoint expects a JSON payload containing an array of run IDs that identify the audio separation tasks you want to retrieve results for:
```json theme={null}
{
"run_ids": [
"12345",
"45678",
"112233"
]
}
```
Each run ID should correspond to a previously initiated audio separation task. The system processes all provided run IDs and returns results for those that have completed successfully.
## Response Structure
The response contains an array of results, where each item corresponds to one of the requested run IDs. For successful separations, each result includes both foreground and background audio URLs:
```json theme={null}
[
12345: {
"foreground_audio_url": "https://storage.example.com/audio/12345_foreground.wav",
"background_audio_url": "https://storage.example.com/audio/12345_background.wav"
},
45678: {
"foreground_audio_url": "https://storage.example.com/audio/45678_foreground.wav",
"background_audio_url": "https://storage.example.com/audio/45678_background.wav"
}
]
```
**Understanding the Response Fields:**
* **run\_id**: The original run ID you provided in the request
* **status**: Current status of the separation task (completed, failed, processing)
* **foreground\_audio\_url**: Direct download URL for the isolated foreground audio components
* **background\_audio\_url**: Direct download URL for the isolated background audio components
* **error**: Error message explaining why a separation task failed (only present for failed tasks)
## Understanding Separated Audio Components
Each successful audio separation produces two complementary audio files that work together to reconstruct your original recording:
**Foreground Audio Components:**
* Contain dominant audio elements like vocals, speech, or lead instruments
* Represent the primary focus of the recording
* Ideal for creating karaoke tracks, enhancing speech clarity, or isolating musical performances
* Typically contain the most prominent frequency ranges and temporal patterns
**Background Audio Components:**
* Contain ambient sounds, musical accompaniment, or secondary audio elements
* Provide context and support to the foreground elements
* Perfect for creating instrumental tracks, ambient soundscapes, or removing unwanted background noise
* Include the supporting audio texture that gives recordings their full character
### Organizing Separated Audio Collections
```python [expandable] theme={null}
import requests
import os
from typing import List, Dict, Optional
def download_audio(url: str, filepath: str) -> bool:
"""
Download audio file from URL to specified filepath
"""
try:
response = requests.get(url, stream=True)
response.raise_for_status()
with open(filepath, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"Downloaded: {filepath}")
return True
except requests.exceptions.RequestException as e:
print(f"Failed to download {url}: {e}")
return False
def organize_separation_results(run_ids: List[int], output_dir: str) -> Optional[Dict]:
"""
Retrieve and organize multiple audio separation results
Args:
run_ids: List of run IDs to fetch results for
output_dir: Directory to save organized results
Returns:
Dictionary containing organized results or None if request fails
"""
try:
# Make API request
response = requests.post(
"https://client.camb.ai/apis/audio-separation-results",
headers={"x-api-key": "YOUR_API_KEY_HERE", "Content-Type": "application/json"},
json={"run_ids": run_ids},
)
response.raise_for_status()
results = response.json()
# Create main output directory
os.makedirs(output_dir, exist_ok=True)
organized_results = {}
# Process each result (key is run_id as string, value is the result data)
for run_id_str, result_data in results.items():
run_id = int(run_id_str)
# Create directory for this separation
run_dir = os.path.join(output_dir, f"run_{run_id}")
os.makedirs(run_dir, exist_ok=True)
# Download foreground audio
foreground_url = result_data["foreground_audio_url"]
foreground_path = os.path.join(run_dir, "foreground.flac")
foreground_success = download_audio(foreground_url, foreground_path)
# Download background audio
background_url = result_data["background_audio_url"]
background_path = os.path.join(run_dir, "background.flac")
background_success = download_audio(background_url, background_path)
# Store organized result info
organized_results[run_id] = {
"directory": run_dir,
"foreground_url": foreground_url,
"background_url": background_url,
"foreground_path": foreground_path if foreground_success else None,
"background_path": background_path if background_success else None,
"download_success": foreground_success and background_success,
}
status = "✓" if organized_results[run_id]["download_success"] else "✗"
print(f"{status} Organized separation results for run_id {run_id}")
print(f"\nProcessed {len(organized_results)} separation results")
print(f"Results saved to: {output_dir}")
return organized_results
except requests.exceptions.HTTPError as e:
print(f"HTTP Error {e.response.status_code}: {e.response.text}")
return None
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
def print_summary(organized_results: Dict) -> None:
"""
Print a summary of organized results
"""
print("\n" + "=" * 50)
print("AUDIO SEPARATION RESULTS SUMMARY")
print("=" * 50)
successful_downloads = 0
failed_downloads = 0
for run_id, result in organized_results.items():
status = "SUCCESS" if result["download_success"] else "FAILED"
print(f"Run ID {run_id}: {status}")
print(f" Directory: {result['directory']}")
if result["download_success"]:
successful_downloads += 1
print(f" Foreground: {result['foreground_path']}")
print(f" Background: {result['background_path']}")
else:
failed_downloads += 1
print("Download failed for one or both audio files")
print()
print(f"Total: {len(organized_results)} results")
print(f"Successful: {successful_downloads}")
print(f"Failed: {failed_downloads}")
# Example usage
if __name__ == "__main__":
# Example run IDs from your response
run_ids_to_process = [112233, 456789]
output_directory = "./audio_separation_results"
# Organize the results
results = organize_separation_results(run_ids_to_process, output_directory)
if results:
print_summary(results)
# Example: Get all foreground audio paths for further processing
foreground_paths = [
result["foreground_path"]
for result in results.values()
if result["foreground_path"]
]
if foreground_paths:
print("\nForeground audio files ready for processing:")
for path in foreground_paths:
print(f" - {path}")
```
## Status Management and Error Handling
When working with bulk audio separation results, individual tasks within your batch may have different statuses. The endpoint returns results for all requested run IDs, but some may not be ready yet or may have encountered processing errors.
**Common Status Scenarios:**
* **Mixed Status Results**: Some separations completed while others are still processing
* **Invalid Run IDs**: Non-existent run IDs will be marked with appropriate error status
* **Processing Failures**: Some audio files may fail separation due to format issues or processing errors
* **Expired URLs**: Older completed separations may have expired download URLs
**Best Practices for Status Management:**
1. Always check the status field before attempting to download audio files
2. Implement retry logic for tasks that are still processing
3. Handle failed separations gracefully with appropriate user feedback
4. Store successful results promptly as download URLs may expire
5. Log processing errors for debugging and quality improvement
## Audio Processing Workflow Integration
This bulk endpoint integrates seamlessly into larger audio processing workflows. Consider this typical pattern for handling multiple audio files:
1. **Submit Multiple Separations**: Upload several audio files for separation processing
2. **Collect Run IDs**: Store all returned run IDs from your separation requests
3. **Batch Status Checking**: Use this bulk endpoint to check the status of multiple separations simultaneously
4. **Process Completed Separations**: Download and organize foreground and background audio files
5. **Handle Incomplete Tasks**: Retry processing for failed separations or wait for still-processing tasks
This workflow is particularly effective for:
* **Podcast Production**: Separating speech from background music across multiple episodes
* **Music Production**: Isolating vocals and instruments from multiple tracks
* **Content Analysis**: Processing large audio libraries for machine learning or analysis
* **Accessibility Enhancement**: Creating separate audio tracks for improved accessibility
## Technical Considerations
**Audio Format and Quality:**
The separated audio files are typically delivered in high-quality formats suitable for professional audio editing. Both foreground and background components maintain the original audio quality while providing clean separation between different audio elements.
**File Size and Storage:**
Since each original audio file produces two separate output files (foreground and background), consider storage requirements when processing large batches. The combined size of separated files will be larger than the original due to the dual-track output.
**Download URL Expiration:**
The presigned URLs returned in the response are temporary and will expire after a certain period. Implement prompt download and storage strategies to ensure you don't lose access to your separated audio files.
**Processing Time Considerations:**
Audio separation is a computationally intensive process. When submitting multiple files, processing times can vary based on audio length, complexity, and current system load. The bulk results endpoint helps you efficiently monitor multiple separations without overwhelming the system with frequent individual status checks.
**Quality Optimization:**
The effectiveness of audio separation depends on the characteristics of your original audio. Files with clear distinction between foreground and background elements (like speech over music) typically produce better separation results than complex multi-layered audio with overlapping frequency ranges.
By leveraging this bulk audio separation results endpoint, you can build sophisticated audio processing applications that handle multiple separations efficiently, enabling creative workflows that scale with your audio production needs while maintaining professional quality standards.
# Fetch Dubbing Results in Bulk
Source: https://docs.camb.ai/api-reference/endpoint/fetch-dubbed-runs-info
post /dubbing-results
Retrieves the results of multiple dubbing runs simultaneously using an array of `run_id` values
Efficiently retrieve the results of multiple dubbing tasks in a single API call. This bulk endpoint allows you to fetch completed dubbing results for multiple runs at once, making it ideal for applications that need to process large volumes of content or manage multiple dubbing projects simultaneously.
## Understanding Bulk Dubbing Results
When you request the results of multiple completed dubbing tasks, our system returns a comprehensive collection of results, with each entry containing:
* **Dubbed Video**: A complete video file with the original visuals and newly generated voiceover in your target language.
* **Dubbed Audio**: An isolated audio track containing only the synthesized speech in your target language.
* **Complete Transcript**: A detailed, time-coded transcript of the dubbed content with speaker identification.
This bulk approach significantly reduces the number of API calls needed when working with multiple dubbing projects, improving efficiency and reducing latency in your applications.
## Accessing Multiple Dubbed Results
To retrieve results for multiple dubbing tasks, you'll need to provide an array of `run_id` values in the request payload. Each `run_id` uniquely identifies a specific dubbing task that was created through our dubbing pipeline.
### Request Payload Structure
The request body should contain an array of run IDs:
```json theme={null}
{
"run_ids": [12345, 67890, 24680, 13579]
}
```
## Example Request with Python
Here's how to fetch multiple dubbing results using Python:
```python [expandable] theme={null}
import requests
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json",
}
def get_bulk_dubbing_results(run_ids):
"""
Retrieves the results of multiple dubbing tasks in a single request.
Returns a collection of dubbing results with media URLs and transcripts.
"""
payload = {"run_ids": run_ids}
try:
response = requests.post(
"https://client.camb.ai/apis/dubbing-results",
headers=headers,
json=payload,
)
# Verify the request was successful
response.raise_for_status()
# Extract the bulk dubbing results
results_data = response.json()
print(f"Successfully retrieved results for {len(results_data)} dubbing runs")
# Process each result
for key in results_data:
print(f"Run ID: {key}")
print(f"\nVideo URL: {results_data.get(key, {}).get('video_url')}")
print(f"\nAudio URL: {results_data.get(key, {}).get('audio_url')}")
print(f"\nTranscript entries: {len(results_data.get(key, {}).get('transcript', []))}")
return results_data
except requests.exceptions.RequestException as e:
print(f"Error retrieving bulk dubbing results: {e}")
if hasattr(e, "response") and e.response is not None:
print(f"Response content: {e.response.text}")
return None
# Example usage with multiple run IDs
run_ids = [41707, 40413] # Replace with your actual run IDs
bulk_results = get_bulk_dubbing_results(run_ids)
# Process successful results
if bulk_results:
print(f"\n{len(bulk_results)} runs completed successfully:")
for result in bulk_results:
run_id = result
transcript = bulk_results.get(run_id, {}).get("transcript", [])
if transcript:
print(f"\nRun ID {run_id} - Transcript Preview:")
for i, dialogue in enumerate(transcript[:2]): # Show first 2 entries
speaker = dialogue.get("speaker", "Unknown")
text = dialogue.get("text", "")
start = dialogue.get("start", "")
end = dialogue.get("end", "")
print(f" Speaker {speaker}: {text} [{start} - {end}]")
if len(transcript) > 2:
print(f" ... and {len(transcript) - 2} more dialogue entries")
```
## Response Handling
The bulk endpoint returns results for all requested run IDs, including those that may still be processing or have failed. Each result in the response includes:
* `video_url`: URL to the dubbed video (if completed)
* `audio_url`: URL to the dubbed audio (if completed)
* `transcript`: Complete transcript with timing information (if completed)
## Best Practices
When using the bulk dubbing results endpoint:
* **Batch Size**: Limit your requests to reasonable batch sizes (recommended: 50-100 run IDs per request) to ensure optimal performance
* **Status Checking**: Always check the status of each result before attempting to access media URLs or transcripts
* **Error Handling**: Implement proper error handling for individual failed runs within the bulk response
This bulk approach streamlines your workflow when managing multiple dubbing projects, reducing API overhead and improving the efficiency of your content localization pipeline.
# Fetch Project Setup Results
Source: https://docs.camb.ai/api-reference/endpoint/fetch-project-setup-runs-results
post /project-setup-results
Retrieve comprehensive setup results for multiple localization projects in a single API call, streamlining project management in CAMB.AI Studio.
## Overview
he **Get Bulk Project Setup Results** endpoint is your go-to tool for managing multiple content localization projects with ease. By retrieving comprehensive setup results for multiple projects in a single API call, this endpoint empowers project managers, content creators, and automation workflows to stay on top of large-scale localization efforts in [CAMB.AI Studio](https://studio.camb.ai).
With this endpoint, you can:
* Retrieve detailed setup results for multiple projects simultaneously.
* Gain insights into project readiness, including status, duration, and language configurations.
**Why Use This Endpoint?**
This endpoint is a game-changer for teams managing multiple localization projects. It provides a unified view of your project portfolio, helping you coordinate tasks, allocate resources efficiently, and make data-driven decisions to keep your content pipeline on track.
```python [expandable] theme={null}
import requests
from typing import Any
def fetch_bulk_story_results(run_ids: list[int]) -> dict[str, Any] | None:
"""
Retrieves multiple story conversion outputs in a single request
Args:
run_ids: List of unique run identifiers from story processing tasks
Returns:
List of story result dictionaries, or None if request fails
"""
headers = {
"x-api-key": "your-api-key-here",
"Content-Type": "application/json",
}
payload = {"run_ids": run_ids}
try:
response = requests.post(
"https://client.camb.ai/apis/stories-results",
headers=headers,
json=payload,
)
response.raise_for_status()
results = response.json()
print(f"Retrieved {len(results)} story results successfully")
return results
except requests.exceptions.HTTPError as e:
print(f"Error {e.response.status_code}: {e.response.text}")
return None
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
def process_bulk_results(results: dict[str, Any]) -> None:
"""
Process and display bulk story results
Args:
results: List of story result dictionaries
"""
for i, run_id_key in enumerate(results, start=1):
print(f"\n--- Story {i} ---")
print(f"Main Audio: {results.get(run_id_key, {}).get('audio_url')}")
print(f"Dialogue Track: {results.get(run_id_key, {}).get('dialogue_url')}")
transcription = results.get(run_id_key, {}).get("transcription", {})
if transcription:
print(f"Transcript entries: {len(transcription)}")
first_entry = transcription[0]
print(
f"First line: [{first_entry['start']}-{first_entry['end']}ms] "
f"{first_entry['speaker']}: {first_entry['text'][:50]}..."
)
# Example usage with multiple run IDs
run_ids_to_fetch = [9872, 9873, 9874, 9875, 9876]
bulk_results = fetch_bulk_story_results(run_ids_to_fetch)
if bulk_results:
process_bulk_results(bulk_results)
# Example: Save audio URLs for batch download
audio_urls = [
bulk_results.get(result, {}).get("audio_url") for result in bulk_results
]
print(f"\nExtracted {len(audio_urls)} audio URLs for batch processing")
```
## Best Practices for Effective Use
To maximize the value of this endpoint, consider these strategies:
1. **Group Projects Strategically**: Organize `run_ids` by priority, language pairs, or deadlines to align with your team's workflow.
2. **Batch Efficiently**: Balance the number of `run_ids` in each request to ensure fast response times and manageable data processing.
# Fetch Stories Results in Bulk
Source: https://docs.camb.ai/api-reference/endpoint/fetch-stories-runs-info
post /stories-results
Efficiently retrieve multiple story conversion outputs simultaneously using a collection of run identifiers
Streamline your workflow by retrieving results from multiple story conversion tasks in a single API call. This bulk endpoint eliminates the need for individual requests when managing large batches of story processing jobs, making it ideal for content management systems, automated publishing workflows, or analytics dashboards that need to aggregate story conversion results.
## Bulk Processing Benefits
This endpoint provides several operational advantages:
* **Reduced API Calls**: Fetch multiple story results with one request
* **Consistent Data Structure**: Uniform response format across all stories
* **Efficient Resource Usage**: Optimized for high-volume story retrieval
* **Batch Processing Support**: Perfect for automated content pipelines
### Request Structure
The endpoint accepts a JSON payload containing an array of run IDs from your story conversion tasks. Each run ID corresponds to a previously submitted story processing job.
All run IDs in the request must be valid and belong to completed story conversion tasks
### Response Format
The API returns an array of story result objects, each containing the same structure as the individual story result endpoint:
* **Full Audio Narration**: Complete audiobook-style recording (`audio_url`)
* **Dialogue-Only Track**: Isolated character conversations (`dialogue_url`)
* **Time-Coded Transcript**: Narrative transcript with speaker attribution (`transcript`)
All retrieved audio links become inaccessible after 24 hours
## Example Python Implementation
Here's how to fetch multiple story results efficiently using Python:
```python [expandable] theme={null}
import requests
from typing import List, Dict, Optional
def fetch_bulk_story_results(run_ids: List[int]) -> Optional[List[Dict]]:
"""
Retrieves multiple story conversion outputs in a single request
Args:
run_ids: List of unique run identifiers from story processing tasks
Returns:
List of story result dictionaries, or None if request fails
"""
headers = {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"run_ids": run_ids
}
try:
response = requests.post(
"https://client.camb.ai/apis/stories-results",
headers=headers,
json=payload
)
response.raise_for_status()
results = response.json()
print(f"Retrieved {len(results)} story results successfully")
return results
except requests.exceptions.HTTPError as e:
print(f"Error {e.response.status_code}: {e.response.text}")
return None
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
def process_bulk_results(results: List[Dict]) -> None:
"""
Process and display bulk story results
Args:
results: List of story result dictionaries
"""
for i, story in enumerate(results, 1):
print(story)
print(f"\n--- Story {i} ---")
print(f"Main Audio: {results[story]['audio_url']}")
print(f"Dialogue Track: {results[story]['dialogue_url']}")
if results[story].get('transcript'):
print(f"Transcript entries: {len(results[story]['transcript'])}")
# Preview first dialogue entry
if results[story]['transcript']:
first_entry = results[story]['transcript'][0]
print(f"First line: [{first_entry['start']}-{first_entry['end']}ms] "
f"{first_entry['speaker']}: {first_entry['text'][:50]}...")
# Example usage with multiple run IDs
run_ids_to_fetch = [240320, 242604]
bulk_results = fetch_bulk_story_results(run_ids_to_fetch)
if bulk_results:
process_bulk_results(bulk_results)
# Example: Save audio URLs for batch download
audio_urls = [bulk_results[story]['audio_url'] for story in bulk_results]
print(f"\nExtracted {len(audio_urls)} audio URLs for batch processing")
```
## Use Cases
This bulk endpoint is particularly valuable for:
* **Content Management Systems**: Retrieving story assets for publication workflows
* **Analytics Dashboards**: Aggregating conversion results for reporting
* **Automated Publishing**: Batch processing completed stories for distribution
* **Quality Assurance**: Bulk validation of story conversion outputs
* **Archive Management**: Collecting completed story assets for long-term storage
# Fetch Subtitle Results
Source: https://docs.camb.ai/api-reference/endpoint/fetch-subtitles-runs-results
post /sub-results
Retrieves the results of multiple subtitle runs using the provided run IDs in the request body.
Fetches subtitle results for several runs in one request. Each run's value matches [Get Subtitle Result](get-subtitle-run-result): structured JSON by default, or exported `srt`/`vtt`/`txt` when you pass `format_type` and/or `data_type`.
* **By default** (no query params) each run returns structured JSON: one language → `{ "transcript": [ ... ] }`; many → object keyed by language ID.
* **When you pass `format_type` and/or `data_type`**, each run is exported the same way as [Get Subtitle Result](get-subtitle-run-result): one language → `{ "transcript": }`; many → `{ "": { "transcript": }, ... }`.
## Choosing your output
| Parameter | Values | Behaviour |
| :------------------- | :------------------------------------------------------ | :------------------------------------- |
| *(none)* | n/a | Per run: structured JSON transcript(s) |
| `data_type=file` | `srt` / `vtt` / `txt` via `format_type` (default `txt`) | Per run: presigned file URL(s) |
| `data_type=raw_data` | `srt` / `vtt` / `txt` via `format_type` (default `txt`) | Per run: rendered text inline |
Same `format_type` / `data_type` values as [Get Transcription Result](get-transcription-run-result) and [Get Subtitle Result](get-subtitle-run-result).
## Request
```json theme={null}
{
"run_ids": [12345, 12346, 12347, 12348]
}
```
## Response Structure
The API returns an object keyed by `run_id`.
### Default (no export params)
```json [expandable] theme={null}
{
"12345": {
"transcript": [
{ "start": 0.0, "end": 2.5, "speaker": "SPEAKER_0", "text": "Welcome to our discussion on AI." }
]
},
"12346": {
"1": {
"transcript": [
{ "start": 0.0, "end": 2.5, "speaker": "SPEAKER_0", "text": "Welcome to our discussion on AI." }
]
},
"23": {
"transcript": [
{ "start": 0.0, "end": 2.7, "speaker": "SPEAKER_0", "text": "Bienvenidos a nuestra discusión sobre IA." }
]
}
}
}
```
| Field | Description |
| :-------- | :-------------------------------------- |
| `start` | Start time of the segment (seconds) |
| `end` | End time of the segment (seconds) |
| `text` | Text for this segment, in that language |
| `speaker` | Speaker identifier |
### Export (`format_type` / `data_type`)
```json theme={null}
{
"12345": { "transcript": "https://storage.example.com/.../output_transcript.srt?..." },
"12346": {
"1": { "transcript": "https://storage.example.com/.../en_us/output_transcript.srt?..." },
"23": { "transcript": "https://storage.example.com/.../es_es/output_transcript.srt?..." }
}
}
```
Presigned file URLs expire after 24 hours.
## Implementation Example
```python [expandable] theme={null}
import requests
headers = {
"x-api-key": "your-api-key",
"Content-Type": "application/json",
}
API_URL = "https://client.camb.ai/apis/sub-results"
run_ids = [12345, 12346, 12347, 12348]
# Default: structured JSON per run
bulk = requests.post(API_URL, headers=headers, json={"run_ids": run_ids}).json()
for run_id, run_result in bulk.items():
if "transcript" in run_result:
print(f"Run {run_id}: {len(run_result['transcript'])} segments")
else:
for language_id, payload in run_result.items():
print(f"Run {run_id} / lang {language_id}: {len(payload['transcript'])} segments")
# Export: SRT file URLs for every language on every run
srt_bulk = requests.post(
API_URL,
headers=headers,
params={"format_type": "srt", "data_type": "file"},
json={"run_ids": run_ids},
).json()
for run_id, run_result in srt_bulk.items():
if "transcript" in run_result:
print(f"Run {run_id}: {run_result['transcript']}")
else:
for language_id, payload in run_result.items():
print(f"Run {run_id} / lang {language_id}: {payload['transcript']}")
```
## Best Practices
* **Batch size**: at least 2 and at most 5 `run_id` values per request
* **Larger sets**: split into chunks of 3–5 and process sequentially to avoid rate limits
## Next Steps
1. [Get Subtitle Result](get-subtitle-run-result) for a single run (same export params)
2. [Get Subtitle Result for Language](get-subtitle-result-for-language) when you only need one language
3. [Create Subtitle](create-subtitle) to start a new run
# Fetch Sound and Music Run Results (Bulk)
Source: https://docs.camb.ai/api-reference/endpoint/fetch-text-to-sound-runs-results
post /text-to-sound-results
Retrieve multiple generated audio files for completed Sound and Music tasks using multiple run IDs.
This endpoint retrieves audio outputs generated from multiple previously completed Sound and Music tasks in a single request. It allows you to efficiently fetch results for several text-to-sound generation runs simultaneously, making it ideal for batch processing workflows and applications that need to handle multiple audio files at once.
Unlike the single result endpoint that takes a run ID as a URL parameter, this bulk endpoint accepts multiple run IDs in the request body, providing a more efficient way to retrieve results when working with multiple text-to-sound tasks.
## How It Works
The endpoint processes an array of run IDs and returns corresponding results for each completed task. This batch approach offers several advantages over making individual requests for each result:
**Efficiency Benefits:**
* Reduces the number of HTTP requests needed
* Minimizes network overhead when fetching multiple results
* Simplifies client-side code for handling multiple audio files
* Provides better performance for applications processing many audio generations
**Practical Applications:**
* Batch processing of multiple text-to-sound requests
* Building audio libraries from multiple text prompts
* Creating soundtracks or audio collections
* Processing results from parallel text-to-sound tasks
## Request Format
The endpoint expects a JSON payload containing an array of run IDs that you want to retrieve results for:
```json theme={null}
// Note: Replace with your actual Run IDs
{
"run_ids": [
"12345",
"678910",
"112233"
]
}
```
Each run ID should correspond to a previously initiated and completed text-to-sound task. The endpoint will process all provided run IDs and return results for those that have completed successfully.
## Response Structure
The response contains an array of results, where each item corresponds to one of the requested run IDs. Each result includes a presigned URL that points directly to the generated audio file:
```json theme={null}
[
12345: {
"output_url": "https://storage.example.com/audio/12345.wav"
},
678910: {
"output_url": "https://storage.example.com/audio/678910.wav"
},
112233: {
"output_url": "https://storage.example.com/audio/112233.wav"
}
]
```
## Example Usage
### Basic Bulk Request
```bash theme={null}
curl -X POST "https://client.camb.ai/apis/text-to-sound-results" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"run_ids": [
"12345",
"678910",
"112233"
]
}'
```
### Processing the Response
```javascript theme={null}
// Example JavaScript code for handling the bulk response
const response = await fetch('/text-to-sound-results', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
run_ids: [
"12345",
"678910",
"112233"
]
})
});
const data = await response.json();
// Process each result
data.results.forEach(result => {
console.log(`Audio ready for ${result}: ${result.output_url}`);
// Download or process the audio file
});
```
## Workflow Integration
This bulk endpoint fits naturally into larger audio processing workflows. Consider this typical pattern:
1. **Initiate Multiple Tasks**: Submit several text-to-sound requests using the creation endpoint
2. **Store Run IDs**: Keep track of all returned run IDs from your requests
3. **Process Completed Results**: Download and handle audio files for completed tasks
4. **Retry or Handle Failures**: Manage any failed tasks or retry processing tasks
## Technical Considerations
**File Format and Quality:**
The generated audio files are delivered in WAV format, providing high audio quality suitable for professional applications. Keep in mind that WAV files are larger than compressed formats but offer the best fidelity for your generated sound effects.
**URL Expiration:**
The presigned URLs returned in the response are temporary and will expire after a certain period. Make sure to download and store important audio files promptly to avoid losing access to your generated content.
**Rate Limiting:**
While this endpoint allows bulk retrieval, be mindful of the fact that this endpoint allows providing a maximum of 5 run IDs per request. The bulk approach is more efficient than individual requests, but extremely large batches should be broken down into manageable chunks.
**Memory and Storage:**
When downloading multiple audio files, consider the memory and storage requirements on your system. Implement appropriate streaming or chunked download strategies for large batches to avoid overwhelming your application's resources.
By leveraging this bulk results endpoint, you can build more efficient applications that handle multiple text-to-sound generations seamlessly, enabling creative workflows that scale with your audio production needs.
# Fetch Transcription Results
Source: https://docs.camb.ai/api-reference/endpoint/fetch-transcriptions-runs-results
post /transcription-results
Retrieves the results of multiple transcription runs using the provided run IDs in the request body.
Access multiple transcription results simultaneously through this powerful bulk endpoint. When your transcription processes complete, this API provides comprehensive text representations of your audio or video content with precise timing information and speaker identification for each run. This bulk retrieval capability streamlines workflows for content creators managing multiple transcription projects, enabling efficient processing of large-scale media libraries.
## Efficient Bulk Processing
Managing multiple transcription projects becomes seamless with bulk retrieval functionality. Our system delivers transcriptions for multiple runs that include:
* **Parallel Processing**: Retrieve results from multiple transcription runs in a single request
* **Temporal Precision**: Exact start and end timestamps for each spoken segment across all runs
* **Speaker Differentiation**: Clear identification of different speakers throughout each piece of content
* **Verbatim Text**: Accurate textual representation of all spoken content for each run
This structured approach to bulk transcription retrieval enables content creators, researchers, and educators to efficiently work with multiple audio-visual materials simultaneously, making entire content libraries searchable, analyzable, and more accessible.
## Retrieving Multiple Transcription Results
To access your completed transcriptions in bulk, you'll need the unique `run_id` values that were assigned when you initially submitted your transcription requests. These identifiers allow our system to locate your specific transcription results within our processing infrastructure and return them as a consolidated response.
### Understanding the Request Structure
The bulk transcription endpoint requires a JSON payload containing an array of run IDs. This allows you to specify exactly which transcription results you want to retrieve:
```json theme={null}
{
"run_ids": [12345, 12346, 12347, 12348]
}
```
### Response Structure
The API returns an array of transcription results, where each element corresponds to one of the requested run IDs. Each transcription result contains an array of dialogue items with detailed timing and speaker information:
| Field | Description |
| :-------- | :--------------------------------------------------------------- |
| `start` | The precise starting point of the speech segment (in seconds) |
| `end` | The exact ending point of the speech segment (in seconds) |
| `text` | The verbatim transcription of the spoken content in this segment |
| `speaker` | Identifier for the person speaking during this segment |
Let's explore how to retrieve and work with bulk transcription data using Python:
```python [expandable] theme={null}
"""
Bulk Transcription Analysis Tool
This script helps you:
1. Fetch multiple transcription results from the CAMB.AI API
2. Analyze the transcriptions (duration, speakers, content)
3. Export transcriptions to CSV files
4. Find common speakers and words across all transcriptions
Before running:
- Replace "your-api-key" with your actual API key
- Install required packages: pip install requests
"""
import requests
import csv
from collections import Counter
import re
# ============================================================================
# CONFIGURATION - Update these values before running
# ============================================================================
# Your API authentication details
headers = {
"x-api-key": "your-api-key", # 🔑 REPLACE WITH YOUR ACTUAL API KEY
"Content-Type": "application/json",
}
# The API endpoint for fetching transcription results
API_URL = "https://client.camb.ai/apis/transcription-results"
# ============================================================================
# MAIN FUNCTIONS
# ============================================================================
def get_bulk_transcriptions(run_ids):
"""
Fetches multiple transcription results from the API in a single request.
This function sends a list of run IDs to the API and gets back all the
transcription data for those runs at once, which is much faster than
making individual requests for each run.
Parameters:
run_ids (list): A list of numbers representing the run IDs you want to fetch
Example: [12345, 12346, 12347]
Returns:
dict: A dictionary where each key is a run ID and each value contains
the transcription data for that run. Returns None if there's an error.
Example response structure:
{
"12345": {
"transcript": [
{"start": 0.0, "end": 2.5, "speaker": "Speaker_1", "text": "Hello world"},
{"start": 2.5, "end": 5.0, "speaker": "Speaker_2", "text": "How are you?"}
]
}
}
"""
try:
# Prepare the data to send to the API
payload = {"run_ids": run_ids}
print(f"📡 Requesting transcriptions for {len(run_ids)} runs...")
# Make the API request
response = requests.post(
API_URL,
headers=headers,
json=payload,
)
# Check if the request was successful (status code 200-299)
response.raise_for_status()
# Convert the response from JSON to a Python dictionary
results = response.json()
# Show the raw response for debugging (you can comment this out later)
print("📋 Raw API response:")
print(results)
print()
print(f"✅ Successfully retrieved {len(results)} transcription results")
return results
except requests.exceptions.RequestException as e:
# This handles network errors, API errors, etc.
print(f"❌ Error retrieving bulk transcriptions: {e}")
if hasattr(e, "response") and e.response is not None:
print(f"🔍 Response details: {e.response.text}")
return None
# ============================================================================
# HELPER FUNCTIONS
# ============================================================================
def format_time(seconds):
"""
Converts seconds to a readable HH:MM:SS format.
Parameters:
seconds (float): Time in seconds (e.g., 3661.5)
Returns:
str: Formatted time string (e.g., "01:01:01")
"""
hours = int(seconds // 3600) # Get whole hours
minutes = int((seconds % 3600) // 60) # Get remaining minutes
secs = int(seconds % 60) # Get remaining seconds
# Format with leading zeros (e.g., "01:05:30" instead of "1:5:30")
return f"{hours:02d}:{minutes:02d}:{secs:02d}"
def safe_get_transcript(transcription_data):
"""
Safely extracts the transcript from API response data.
The API returns nested data, so we need to safely navigate to the transcript.
Parameters:
transcription_data (dict): The data for one transcription run
Returns:
list: List of transcript segments, or empty list if not found
"""
if not transcription_data:
return []
# Navigate safely: transcription_data -> "transcript" -> list of segments
return transcription_data.get("transcript", [])
# ============================================================================
# ANALYSIS FUNCTIONS
# ============================================================================
def analyze_single_transcription(transcription, run_id):
"""
Analyzes a single transcription and prints detailed statistics.
This function examines one transcription result and shows:
- How long the audio was
- How many dialogue segments there are
- Who the speakers are
- Sample dialogue from the beginning
Parameters:
transcription (list): List of dialogue segments from the API
run_id (str): The ID of this transcription run (for display purposes)
"""
# Check if we have any data to analyze
if not transcription:
print(f"🔍 Run {run_id}: No transcription data available")
return
print(f"📊 Analyzing Run {run_id}:")
print("=" * 40)
# Calculate basic statistics
total_duration = max(segment["end"] for segment in transcription) if transcription else 0
total_segments = len(transcription)
# Find all unique speakers in this transcription
speakers = set()
for segment in transcription:
if "speaker" in segment:
speakers.add(segment["speaker"])
unique_speakers = len(speakers)
# Count how many times each speaker appears
speaker_counts = Counter()
for segment in transcription:
if "speaker" in segment:
speaker_counts[segment["speaker"]] += 1
# Find who spoke the most
most_frequent_speaker = speaker_counts.most_common(1)[0][0] if speaker_counts else "Unknown"
# Print all the statistics
print(f" 🕐 Total duration: {format_time(total_duration)}")
print(f" 💬 Total segments: {total_segments}")
print(f" 👥 Unique speakers: {unique_speakers}")
print(f" 🎤 Most frequent speaker: {most_frequent_speaker}")
# Show the first few lines of dialogue as examples
print(" 📝 Sample dialogue:")
for i, segment in enumerate(transcription[:2]): # Show first 2 segments only
start_time = format_time(segment["start"])
end_time = format_time(segment["end"])
speaker = segment.get("speaker", "Unknown")
# Truncate long text to keep output readable
text = segment.get("text", "")
if len(text) > 50:
text = text[:50] + "..."
print(f" [{start_time} → {end_time}] {speaker}: {text}")
print() # Add blank line for readability
def analyze_bulk_transcriptions(transcription_results):
"""
Analyzes all transcription results and provides insights for each one.
This is the main analysis function that processes all the transcriptions
you fetched from the API.
Parameters:
transcription_results (dict): Dictionary of all transcription results from the API
"""
if not transcription_results:
print("❌ No transcription results to analyze")
return
print(f"\n🔍 Analyzing {len(transcription_results)} transcription results:")
print("=" * 60)
# Process each transcription one by one
for run_id in transcription_results:
# Safely extract the transcript data
transcript = safe_get_transcript(transcription_results.get(run_id, {}))
# Analyze this individual transcription
analyze_single_transcription(transcript, run_id)
# ============================================================================
# EXPORT FUNCTIONS
# ============================================================================
def export_transcription_to_csv(transcription, filename):
"""
Export a single transcription to a CSV file for further analysis.
Creates a CSV file with columns: start, end, speaker, text
This makes it easy to open in Excel or other spreadsheet programs.
Parameters:
transcription (list): List of dialogue segments
filename (str): Name of the output file (e.g., "transcription_12345.csv")
"""
if not transcription:
print(f"⚠️ No data to export for {filename}")
return
try:
# Open the file for writing
with open(filename, "w", newline="", encoding="utf-8") as csvfile:
# Define the column headers
fieldnames = ["start", "end", "speaker", "text"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
# Write the header row
writer.writeheader()
# Write each dialogue segment as a row
for segment in transcription:
writer.writerow({
"start": segment.get("start", ""),
"end": segment.get("end", ""),
"speaker": segment.get("speaker", ""),
"text": segment.get("text", ""),
})
print(f"💾 Exported transcription to {filename}")
except Exception as e:
print(f"❌ Error exporting to {filename}: {e}")
# ============================================================================
# CROSS-TRANSCRIPTION ANALYSIS FUNCTIONS
# ============================================================================
def extract_speakers_from_bulk(transcription_results):
"""
Finds all unique speakers across multiple transcription runs.
This helps you understand who appears in your audio content overall.
Parameters:
transcription_results (dict): Dictionary of all transcription results
Returns:
list: List of all unique speaker names found across all transcriptions
"""
all_speakers = set() # Use a set to automatically handle duplicates
# Go through each transcription
for run_id in transcription_results:
transcript = safe_get_transcript(transcription_results.get(run_id, {}))
if transcript:
# Extract speakers from this transcription
for segment in transcript:
if "speaker" in segment:
all_speakers.add(segment["speaker"])
return list(all_speakers) # Convert back to list
def find_common_words(transcription_results, min_length=5):
"""
Identifies frequently used words across multiple transcriptions.
This helps you understand the main topics and themes in your audio content.
Parameters:
transcription_results (dict): Dictionary of all transcription results
min_length (int): Minimum word length to consider (default: 5)
This filters out common short words like "the", "and", etc.
Returns:
Counter: A Counter object with word frequencies
"""
all_words = []
# Go through each transcription
for run_id in transcription_results:
transcript = safe_get_transcript(transcription_results.get(run_id, {}))
if transcript:
# Extract words from each dialogue segment
for segment in transcript:
if "text" in segment:
# Convert to lowercase for consistent counting
text = segment["text"].lower()
# Extract words (letters only, no punctuation)
words = re.findall(r"\b\w+\b", text)
# Only keep words that are long enough
filtered_words = [word for word in words if len(word) >= min_length]
all_words.extend(filtered_words)
# Count how many times each word appears
word_counts = Counter(all_words)
# Display the results
print("\n📈 Most common words across all transcriptions:")
print("-" * 45)
for word, count in word_counts.most_common(10): # Show top 10
print(f" {word}: {count} occurrences")
return word_counts
# ============================================================================
# MAIN EXECUTION
# ============================================================================
if __name__ == "__main__":
"""
Main execution section - this runs when you execute the script directly.
Modify the run_ids list below with your actual run IDs.
"""
print("🚀 Starting Bulk Transcription Analysis Tool")
print("=" * 50)
# ⚠️ MODIFY THIS LIST WITH YOUR ACTUAL RUN IDs
run_ids = [12345, 12346, 12347, 12348]
print(f"📋 Processing run IDs: {run_ids}")
print()
# Step 1: Fetch all transcription results from the API
print("🔄 Step 1: Fetching transcription results...")
bulk_results = get_bulk_transcriptions(run_ids)
if bulk_results:
print("✅ Successfully fetched results. Starting analysis...")
# Step 2: Analyze all transcription results
print("\n🔄 Step 2: Analyzing transcriptions...")
analyze_bulk_transcriptions(bulk_results)
# Step 3: Export each transcription to a separate CSV file
print("\n🔄 Step 3: Exporting transcriptions to CSV files...")
for run_id in bulk_results:
transcript = safe_get_transcript(bulk_results.get(run_id, {}))
if transcript:
filename = f"transcription_run_{run_id}.csv"
export_transcription_to_csv(transcript, filename)
# Step 4: Find all speakers across all transcriptions
print("\n🔄 Step 4: Finding all speakers...")
all_speakers = extract_speakers_from_bulk(bulk_results)
print(f"👥 All speakers across {len(bulk_results)} runs: {all_speakers}")
# Step 5: Analyze common vocabulary
print("\n🔄 Step 5: Analyzing common vocabulary...")
find_common_words(bulk_results)
print("\n🎉 Analysis complete! Check the CSV files for detailed transcription data.")
else:
print("❌ Failed to fetch transcription results. Please check your API key and run IDs.")
```
## Bulk Processing Benefits
The bulk transcription endpoint provides several advantages for managing multiple transcription projects:
### Workflow Efficiency
* **Single Request**: Retrieve multiple transcription results without making separate API calls
* **Reduced Latency**: Minimize network overhead by consolidating requests
* **Batch Processing**: Perfect for processing entire content libraries or project collections
### Content Management
* **Comparative Analysis**: Easily compare transcriptions across multiple runs
* **Consolidated Reporting**: Generate unified reports from multiple transcription sources
* **Quality Assurance**: Streamline review processes for large-scale transcription projects
### Integration Capabilities
* **Database Population**: Efficiently populate content databases with transcription data
* **Search Indexing**: Build comprehensive search indexes across multiple content pieces
* **Analytics Processing**: Perform cross-content analysis and pattern recognition
## Best Practices for Bulk Processing
To maximize the effectiveness of bulk transcription retrieval:
### Request Optimization
* **Batch Size**: Request reasonable batch sizes (typically 3-5 runs per request)
* **Run Grouping**: Group related runs together for more efficient processing
* **Retry Logic**: Implement retry mechanisms for handling temporary failures
### Data Management
* **Result Caching**: Cache frequently accessed transcription results
* **Incremental Processing**: Process new runs while maintaining existing data
* **Storage Strategy**: Implement efficient storage solutions for large transcription datasets
### Performance Considerations
* **Parallel Processing**: Use the bulk endpoint instead of multiple individual requests
* **Memory Management**: Process large result sets in chunks to manage memory usage
* **Rate Limiting**: Respect API rate limits when making frequent bulk requests
# Fetch Translation Results in Bulk
Source: https://docs.camb.ai/api-reference/endpoint/fetch-translation-runs-results
post /translation-results
Retrieves the final translated texts from multiple completed translation tasks using a list of `run_id` values in a single request.
This endpoint delivers the final products of multiple translation processes simultaneously: all your translated texts in one efficient request. Once your translation tasks have completed successfully and you've received multiple `run_id` values, this endpoint allows you to retrieve all the actual translations that were generated. Think of it as the express pickup counter where you collect several finished translation orders at once, rather than making individual trips for each one.
## How to Use This Endpoint
To retrieve multiple sets of translated texts, send a `POST` request to this endpoint with an array of `run_id` values in the request body. Each `run_id` serves as your claim ticket for a finished translation task. You must provide between 2 and 5 `run_id` values per request. The system will respond with a structured object containing all your translated texts, organized by their corresponding `run_id` values.
## Request Format
The request body should contain an array of `run_id` values for the completed translation tasks you want to retrieve. You must provide between 2 and 5 `run_id` values per request:
```json theme={null}
{
"run_ids": [12345, 12346, 12347, 12348]
}
```
The `run_ids` array must contain between 2 and 5 values. Requests with fewer than 3 or more than 5 run\_ids will be rejected with a validation error.
## Understanding the Response
When you call this endpoint, you'll receive a response that includes all your translated content organized by `run_id`:
* **`results`**: An object where each key is a `run_id` and each value contains the translation data for that specific task
* **`texts`**: Within each result, an array of strings containing the translated output texts, maintaining the same order as the original input for that task
The structure of the response follows this format:
```json [expandable] theme={null}
{
"12345": {
"texts": [
"Your first translated text from task 12345",
"Your second translated text from task 12345"
]
},
"12346": {
"texts": [
"Your first translated text from task 12346",
"Your second translated text from task 12346",
"Your third translated text from task 12346"
]
},
"12347": {
"texts": [
"Single translated text from task 12347"
]
},
"12348": {
"texts": [
"First text from task 12348",
"Second text from task 12348",
"Third text from task 12348",
"Fourth text from task 12348"
]
}
}
```
This structured response format makes it simple to process multiple translation tasks while maintaining clear organization. You can easily access translations for any specific task or iterate through all results systematically.
## Working with Bulk Translation Results
There are several effective patterns for handling bulk translation results:
### Direct Processing
For immediate use, you can extract and process all translation results:
```python [expandable] theme={null}
# Welcome to the translation results retriever! 🌍✨
# This script will help you get translation results for multiple tasks from the Camb AI API.
# Make sure you have the requests library installed. If not, run: pip install requests 📦
import requests
# Set up the headers for the API request. This includes your API key and the content type. 🔑
# TODO: Replace 'your-api-key' with your actual API key from Camb AI.
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json",
}
# List of run_ids for the completed translation tasks you want to retrieve. 📋
# TODO: Replace these with your actual run_ids. Must be between 2 and 5 run_ids.
run_ids = [12345, 12346, 12347, 12348] # Example run_ids
def get_bulk_translation_results(run_ids):
"""
Retrieves translations for multiple completed tasks in a single request. 🚀
Args:
run_ids: List of run_id values for completed translation tasks (must be 3-5 items)
Returns:
dict: Dictionary mapping run_ids to their translation results
"""
# Check if the number of run_ids is between 2 and 5. If not, print an error message and return an empty dictionary. ⚠️
if len(run_ids) < 2 or len(run_ids) > 5:
print(
f"❌ Error: Must provide between 2 and 5 run_ids. You provided {len(run_ids)}."
)
return {}
print(f"🌟 Retrieving translations for {len(run_ids)} completed tasks...")
# Prepare the payload for the API request. This includes the list of run_ids. 📦
payload = {"run_ids": run_ids}
try:
# Define the API endpoint URL. 🌐
API_URL = "https://client.camb.ai/apis/translation-results"
# Make the POST request to the API endpoint to retrieve the translation results. 🚀
response = requests.post(API_URL, headers=headers, json=payload)
# Check if the request was successful. If not, an exception will be raised. ✅
response.raise_for_status()
# Parse the JSON response to get the translation results. 📄
results = response.json()
print(f"🎉 Successfully retrieved translations for {len(results)} tasks!")
return results
except requests.exceptions.RequestException as e:
print(f"😢 Oops! There was an error retrieving the translation results: {e}")
return {}
# Now, let's retrieve the translation results for the provided run_ids. 🌟
translation_results = get_bulk_translation_results(run_ids)
# Check if any results were retrieved. If not, print a message. 🤔
if not translation_results:
print(
"😞 No translation results were retrieved. Please check your run_ids and API key."
)
else:
# Process the retrieved translation results and print them. 🖨️
for run_id in translation_results:
translations = translation_results.get(run_id, {}).get("texts", [])
print(f"\n🎉 Run ID {run_id} has {len(translations)} translations:")
for i, translation in enumerate(translations):
print(f" {i+1}. {translation} 🌍")
# What's next? You could save these results to a file or use them in your next project! 🚀
```
## Best Practices
### Request Size Requirements
This endpoint requires a specific batch size for optimal performance and resource management:
* **Minimum**: You must provide at least 2 `run_id` values per request
* **Maximum**: You can provide up to 5 `run_id` values per request
* **Validation**: Requests outside this range will be rejected with a validation error
### Handling Larger Datasets
If you have more than 5 completed translation tasks to retrieve:
* **Split into Multiple Requests**: Divide your `run_id` list into chunks of 3-5 items
* **Sequential Processing**: Process chunks sequentially to avoid rate limiting
* **Batch Management**: Implement logic to group your run\_ids efficiently
```python [expandable] theme={null}
# Example: Processing larger datasets
all_run_ids = [12345, 12346, 12347, 12348, 12349, 12350, 12351, 12352]
# Split into chunks of 3-5 run_ids
def chunk_run_ids(run_ids, chunk_size=5):
"""Split run_ids into chunks of specified size (3-5)."""
chunks = []
for i in range(0, len(run_ids), chunk_size):
chunk = run_ids[i:i + chunk_size]
if len(chunk) >= 2: # Ensure minimum chunk size
chunks.append(chunk)
elif chunks: # Add remaining items to last chunk if possible
chunks[-1].extend(chunk)
return chunks
# Process in batches
chunks = chunk_run_ids(all_run_ids)
all_results = {}
for i, chunk in enumerate(chunks):
print(f"Processing batch {i+1}/{len(chunks)}: {len(chunk)} run_ids")
batch_results, failed_ids = get_bulk_translation_results_with_error_handling(chunk)
all_results.update(batch_results)
```
### Error Recovery
Always implement proper error handling when working with bulk operations:
* Check response status codes before processing results
* Handle partial failures gracefully (some run\_ids may succeed while others fail)
* Implement retry logic for transient failures
* Log failed run\_ids for later processing
## Next Steps
Once you've retrieved your bulk translation results, you can:
1. **Display them** to your users in organized, task-specific groups
2. **Store them** systematically with proper task organization
3. **Process them further** with additional NLP tools while maintaining task relationships
4. **Use them in your application logic** to enable comprehensive multilingual functionality
The structured response format makes it easy to integrate multiple translation results wherever they're needed in your workflow, whether you're building a multilingual content management system, an educational platform with batch translation capabilities, or an international communication tool that processes multiple conversation threads.
By understanding how to effectively use this bulk endpoint, you can create highly efficient multilingual applications that deliver multiple sets of high-quality translations to your users in a single, streamlined operation.
# Fetch Bulk Text-to-Speech Results
Source: https://docs.camb.ai/api-reference/endpoint/fetch-tts-runs-results
post /tts-results
Retrieves the results of multiple Text-to-Speech runs using a list of `run_id` values in a single request.
Bulk retrieval only helps when you already have run IDs from the deprecated async `POST /tts` workflow. For anything new, stream each piece of speech with `POST /tts-stream` (split longer copy into segments if needed) instead of batching legacy runs.
This endpoint streamlines the process of retrieving multiple completed audio files at once, perfect for applications that process batches of text-to-speech tasks. Instead of making individual requests for each `run_id`, you can efficiently gather all your generated audio files in a single API call.
## How to Use this Endpoint
Retrieving multiple generated audio files is straightforward - make a `POST` request to this endpoint with an array of `run_id` values in the request body. The system will process all your completed tasks and return URLs for each audio file, making it easy to download or reference them in your application.
## Understanding the Response
This endpoint returns a JSON response containing file URLs for each successfully processed run\_id. Each audio file URL in the response corresponds to a completed text-to-speech task, allowing you to efficiently handle multiple audio files without the overhead of individual requests.
The bulk response structure provides:
* **Organized Results:** Each `run_id` is mapped to its corresponding audio file URL.
* **Error Handling:** Clear indication of any failed or unavailable runs.
* **Efficient Processing:** Single request handles multiple audio files.
This bulk endpoint is particularly useful for applications that generate multiple audio segments simultaneously, such as creating audiobook chapters, processing multiple language versions, or handling batch content generation.
## Request Format
The request body should contain an array of `run_id` values for the completed text-to-speech tasks you want to retrieve:
```json theme={null}
{
"run_ids": [12345, 12346, 12347, 12348]
}
```
### Response Structure
The response will be a JSON object containing URLs for each successfully processed audio file:
```json theme={null}
{
"12345": "https://audio-storage.camb.ai/files/audio_12345.flac",
"12346": "https://audio-storage.camb.ai/files/audio_12346.flac",
"12347": "https://audio-storage.camb.ai/files/audio_12347.flac",
"12348": "https://audio-storage.camb.ai/files/audio_12348.flac"
}
```
File URLs have an expiration time, so download or use them promptly rather than storing them long-term. Plan to process your audio files within a reasonable timeframe after retrieval.
## Examples
### Retrieving Multiple Audio Files
Here's how to retrieve multiple generated audio files using Python:
```python [expandable] theme={null}
import requests
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json",
}
# List of run_ids from your completed TTS tasks (must be between 2-5 run_ids)
run_ids = [12345, 12346, 12347, 12348] # Replace with your actual run_ids
def get_bulk_audio_results(run_ids):
"""
Retrieves URLs for multiple completed TTS tasks in a single request.
Args:
run_ids: List of run_id values for completed TTS tasks (must be 2-5 items)
Returns:
dict: Dictionary mapping run_ids to their audio file URLs
"""
# Validate the number of run_ids
if len(run_ids) < 2 or len(run_ids) > 5:
print(
f"Error: Must provide between 2 and 5 run_ids. You provided {len(run_ids)}."
)
return {}
print(f"Retrieving audio URLs for {len(run_ids)} completed tasks...")
# Prepare the request payload
payload = {"run_ids": run_ids}
try:
# Make the POST request
response = requests.post(
"https://client.camb.ai/apis/tts-results",
headers=headers,
json=payload,
)
# Check if the request was successful
response.raise_for_status()
# Parse the response
results = response.json()
print(f"Successfully retrieved {len(results)} audio file URLs!")
return results
except requests.exceptions.RequestException as e:
print(f"Error retrieving bulk audio results: {e}")
return {}
# Retrieve all audio URLs
audio_urls = get_bulk_audio_results(run_ids)
# Process the results
for run_id, output_json in audio_urls.items():
print(f"Run ID {run_id}: {output_json.get('output_url')}")
```
## Best Practices
### Request Size Requirements
This endpoint requires a specific batch size for optimal performance and resource management:
* **Minimum**: You must provide at least 2 `run_id` values per request
* **Maximum**: You can provide up to 5 `run_id` values per request
* **Validation**: Requests outside this range will be rejected with a validation error
### Handling Larger Datasets
If you have more than 5 completed TTS tasks to retrieve:
* **Split into Multiple Requests**: Divide your `run_id` list into chunks of 2-5 items
* **Sequential Processing**: Process chunks sequentially to avoid rate limiting
* **Batch Management**: Implement logic to group your run\_ids efficiently
## Next Steps
With your bulk audio retrieval capabilities in place, you can:
1. **Build Efficient Workflows**: Process multiple audio files simultaneously in your applications
2. **Create Batch Processing Systems**: Handle large-scale content generation with minimal API overhead
3. **Implement Robust Error Handling**: Ensure your application gracefully handles partial failures
4. **Optimize Resource Usage**: Reduce API calls and improve application performance
This bulk endpoint provides the foundation for scalable voice applications that can handle multiple audio files efficiently and reliably.
# Get Audio Separation Result
Source: https://docs.camb.ai/api-reference/endpoint/get-audio-separation-run-info
get /audio-separation-result/{run_id}
Retrieves detail information about a specific audio separation run using the provided `run_id`.
# Accessing Your Separated Audio Components
Once your audio separation task completes successfully, this endpoint provides immediate access to the isolated audio components. The system divides your original audio into two distinct tracks: a **foreground** track containing primary audio elements (typically speech, vocals or main instruments) and a **background** track with remaining audio elements. These isolated components enable creative flexibility for remixing, enhancing specific audio elements, or removing unwanted sounds from your original recording.
## Understanding Audio Separation Results
* **Foreground Audio**: Contains dominant audio elements, typically vocals, speech, or lead instruments that represent the primary focus of the recording
* **Background Audio**: Contains ambient sounds, musical accompaniment, or secondary audio elements that provide context or support to the foreground elements
Audio separation technology analyzes the spectral and temporal characteristics of your audio file to identify and isolate different sound components. The separation process creates two complementary audio files that, when combined, reconstruct your original recording:
* **Foreground Audio**: Contains dominant audio elements, typically vocals, speech, or lead instruments that represent the primary focus of the recording
* **Background Audio**: Contains ambient sounds, musical accompaniment, or secondary audio elements that provide context or support to the foreground elements
This dual-track approach gives you unprecedented control over your audio content for professional editing, creative remixing, or accessibility enhancements.
## Retrieving Separated Audio Files
After your separation task completes, you'll receive a `run_id` that serves as your access key to the processed audio files. Simply make a GET request to this endpoint using that identifier to retrieve download URLs for both audio components.
### Response Structure
A successful response returns direct download URLs for both the foreground and background audio files:
```json theme={null}
{
"foreground_audio_url": "",
"background_audio_url": ""
}
```
Each URL points to a standard audio file that can be downloaded directly or streamed into your application.
# Get Audio Separation Task Status
Source: https://docs.camb.ai/api-reference/endpoint/get-audio-separation-status
get /audio-separation/{task_id}
Retrieves the current status of an audio separation task using the specified `task_id`.
When you submit an audio file for separation into its component tracks, our system begins processing your request as a background task. This endpoint serves as your window into that process, allowing you to monitor the progression of your audio separation task from initiation to completion.
## Making Status Requests
To check on your audio separation task's progress, you'll need the unique `task_id` that was provided when you initially submitted your separation request. With this identifier, simply make a GET request to the endpoint:
```
GET https://client.camb.ai/apis/audio-separation/{task_id}
```
## Troubleshooting Common Issues
If you encounter difficulties while checking separation status, consider these common solutions:
1. **Invalid Task ID**: Verify the task ID was correctly stored and passed to the status endpoint. Task IDs are case-sensitive and must be used exactly as provided.
2. **Authentication Problems**: Ensure your API key is valid and correctly included in the request headers.
3. **Network Connectivity**: Implement proper error handling for network issues that might interrupt status checking, including automatic retry logic.
4. **Unexpected Terminal States**: If a separation ends with an error status, examine the error message for specific issues that might be addressed in subsequent separation attempts.
By properly integrating status checking into your application, you can create a seamless separation experience that keeps your users informed throughout the entire process, building confidence in your service and ensuring timely delivery.
# Get Dictionary Full Details
Source: https://docs.camb.ai/api-reference/endpoint/get-dictionary-full-details
get /dictionaries/{dictionary_id}/full-details
Retrieves comprehensive details for a specific dictionary, including all terms and their definitions. Supports optional filtering and pagination to help you find exactly what you need.
## Overview
This endpoint provides you with complete access to a dictionary's content, returning detailed information about the dictionary itself along with all its terms and definitions. Think of this as opening up a physical dictionary and having access to browse through all its entries, but with the added convenience of being able to search for specific terms or limit how many results you see at once.
## Understanding Dictionary Details
When you request full details for a dictionary, you're essentially asking the system to compile a comprehensive view that includes both the dictionary's metadata (information about the dictionary itself) and its complete content. This content consists of all the dictionary's terms along with their corresponding translations or definitions. Think of it as getting both the book's cover information and all the pages inside, delivered together in one complete package.
This comprehensive approach is particularly valuable when you're building multilingual applications, translation tools, or terminology management systems where you need access to both the source terms and their translated equivalents. The full details endpoint delivers this rich content in a structured format that makes it easy to work with term-translation pairs programmatically.
The "full details" approach means you get everything in one request rather than having to make separate calls for dictionary information and then additional calls for each term and its translations. This design helps reduce the number of API calls your application needs to make, which improves performance and simplifies your code while giving you complete access to the dictionary's linguistic content.
# Get Dictionary Summary
Source: https://docs.camb.ai/api-reference/endpoint/get-dictionary-summary
get /dictionaries/{dictionary_id}
Retrieves essential information about a specific dictionary, including its name, description, and metadata. Perfect for getting a quick overview without loading all dictionary terms.
## Overview
Think of this endpoint as looking at the cover and introduction of a book before deciding whether to read the entire thing. When you need to understand what a dictionary contains and when it was created or last modified, but don't need to see all its terms and definitions, this endpoint provides exactly that focused information.
This summary approach serves a fundamentally different purpose than retrieving full dictionary details. While the full details endpoint gives you everything including all terms and definitions, this summary endpoint focuses exclusively on the dictionary's identifying characteristics and metadata. This distinction becomes important when you're building applications that need to display dictionary information efficiently or when you're working with multiple dictionaries and need to present them in lists or selection interfaces.
## Understanding Dictionary Metadata
Every dictionary in the system carries essential information about itself, separate from the actual terms and definitions it contains. This metadata tells the story of the dictionary: what it's called, what it's intended for, when it was created, and when someone last made changes to it. Understanding this information helps you and your users make informed decisions about which dictionaries to work with and whether the content might be current for your needs.
The metadata approach also supports better application architecture. Instead of loading potentially thousands of dictionary terms just to show a user what dictionaries are available, you can quickly retrieve just the summary information for multiple dictionaries, creating responsive user interfaces that load quickly and provide clear choices.
# Get Dubbed Output in Alt Format
Source: https://docs.camb.ai/api-reference/endpoint/get-dub-alt-format
post /dub-alt-format/{run_id}/{language}
Fetches the dubbed output for a specified `run_id` and `language` in the file format that is provided in the request body.
Convert your already-dubbed content into alternative file formats with our specialized endpoint. This powerful feature extends the capabilities of our core dubbing service by allowing you to repurpose completed dubbing projects into different media formats. Whether you need audio-only extracts, format conversions for specific platforms, this endpoint provides the flexibility to meet diverse content delivery requirements.
## Understanding Alternative Format Exports
The alt format endpoint works with content that has already been processed through our [`/dub`](end-to-end-dubbing) service:
Use the `run_id` from a completed dubbing task and specify which `language` version you want to convert.
Specify your desired output format and configuration options in the request body.
Our system will extract and convert the requested dubbed content into the specified format.
Receive a download URL for your newly converted content, or a task ID to track processing status.
This endpoint complements the main dubbing workflow, giving you additional flexibility in how you deliver your multilingual content across different platforms and use cases.
# Get Dubbed Output in Alt Format Task Status
Source: https://docs.camb.ai/api-reference/endpoint/get-dub-alt-format-task-status
get /dub-alt-format/{task_id}
Retrieves the current status of a task exporting dubbed media to alternative file formats using the specified `task_id`.
Monitor the progress of your format conversion tasks with our dedicated status tracking endpoint. This essential companion to our format conversion service lets you check on your media transformation in real-time, providing status information about your content conversion process. By polling this endpoint, you can keep track of your format conversion progress and detect any issues that might arise during processing.
This endpoint works in conjunction with the format conversion functionality of our dubbing service, which provides the `task_id` needed for status checks when requesting alternative output formats.
## Understanding Status Values
The endpoint returns one of these status values:
* **`SUCCESS`**: The format conversion task has completed successfully
* **`PENDING`**: The format conversion task is still in progress
* **`TIMEOUT`**: The format conversion task has timed out
* **`ERROR`**: The format conversion task encountered an error
* **`PAYMENT_REQUIRED`**: Additional payment is needed to complete the task
## Implementing Status Checking
Here's how to implement status checking in your application using Python:
```python [expandable] theme={null}
import requests
import json
import time
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def check_format_conversion_status(task_id):
"""
Polls the status endpoint to track a format conversion task's progress.
Continues checking until the task reaches a terminal state.
"""
if not task_id:
print("Error: No task ID provided")
return None
# Define terminal states based on the API specification
terminal_states = ["SUCCESS", "TIMEOUT", "ERROR", "PAYMENT_REQUIRED"]
current_status = None
while current_status not in terminal_states:
try:
# Make the status request
response = requests.get(
f"https://client.camb.ai/apis/dub-alt-format/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Extract the status information
status_data = response.json()
current_status = status_data.get("status")
# Display current status information
print(f"Status: {current_status}")
# Handle success state
if current_status == "SUCCESS":
print("Format conversion task completed successfully!")
print(f"Result URL: {status_data.get('result_url')}")
return status_data
# Handle error states
if current_status == "ERROR":
print(f"Format conversion task failed: {status_data.get('error_message')}")
return status_data
# Handle timeout state
if current_status == "TIMEOUT":
print("Format conversion task timed out")
return status_data
# Handle payment required state
if current_status == "PAYMENT_REQUIRED":
print("Additional payment is required to complete this task")
return status_data
# If still pending, wait before next check
if current_status == "PENDING":
print("Task is still in progress")
# Wait before next check to avoid excessive requests
time.sleep(10) # Poll every 10 seconds
except requests.exceptions.RequestException as e:
print(f"Error checking format conversion status: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
return None
# Example usage with a task_id from a previous format conversion request
task_id = "your_task_id" # Replace with your actual task ID
final_status = check_format_conversion_status(task_id)
```
## Best Practices for Status Monitoring
To efficiently track your format conversion tasks, consider these professional recommendations:
1. **Implement Exponential Backoff**: Start with frequent checks that gradually increase in interval to avoid overloading the API. For example, begin with a 5-second interval, then double it each time until you reach a maximum of 2 minutes between checks.
2. **Handle All Status Codes**: Ensure your implementation has specific handling for each possible status value (`SUCCESS`, `PENDING`, `TIMEOUT`, `ERROR`, and `PAYMENT_REQUIRED`).
3. **Graceful Error Recovery**: If the format conversion fails, implement logic to retry the operation or provide clear feedback to users about the next steps they should take.
4. **User Interface Integration**: Present status updates in a user-friendly way, such as progress indicators or status messages that translate the technical status codes into more accessible language.
5. **Event Logging**: Maintain a detailed log of all status changes to help with troubleshooting if issues arise during the conversion process.
By properly integrating status checking into your application, you can create a seamless media conversion experience that keeps your users informed throughout the entire process and handles both successful and unsuccessful outcomes appropriately.
# Get Dubbing Transcript
Source: https://docs.camb.ai/api-reference/endpoint/get-dub-transcript
get /transcript/{run_id}/{language}
Retrieves the transcript in the specified language of a specific end to end dubbing run using the provided `run_id`.
This endpoint serves as a bridge between your media content and its written representation. When you've completed a dubbing run using Camb.ai's powerful dubbing technology, it gives you access to all that valuable spoken content in text form, unlocking new possibilities for how you can use and share your content.
The `{language}` path parameter is your language selector. It determines which linguistic version of your transcript you'll receive - you can choose either the original source language or any of the target languages you've dubbed your content into.
## Understanding Response Options
The transcript endpoint gives you two distinct ways to receive your transcript data, each designed for different implementation scenarios:
* **Direct content delivery** (`data_type=raw_data`): The transcript text comes straight to you as `{ "transcript": "" }` in the JSON response body. This immediate delivery is perfect for when you need to process or display the text right away in your application.
* **File-based delivery** (`data_type=file`): You receive `{ "transcript": "" }` linking to a ready-to-download transcript file. This approach works wonderfully when you need to store, share, or download the transcript as a distinct file.
In both cases the value lives under the `transcript` key — read it with `response.json()["transcript"]`. Your choice between these options depends on your workflow and how you intend to use the transcript data in your application.
## Choosing the Right Format for Your Needs
Transcripts come in three carefully designed formats, each optimized for different applications:
| Format | Description | Ideal Applications |
| :-------------- | :-------------------------------------------------- | :-------------------------------------------------------------------------------------- |
| `txt` (default) | Clean, simple plain text without timing information | Content analysis, text extraction, SEO optimization, and general reading |
| `srt` | SubRip Subtitle format with precise timestamps | Professional video editing software, most desktop video players, and subtitle embedding |
| `vtt` | WebVTT format optimized for web environments | HTML5 video players, web applications, and accessibility compliance on websites |
The format you choose should align with how you plan to use the transcript. For example, if you're adding subtitles to a web video player, WebVTT (`vtt`) would be your best choice because of its native support in HTML5 environments. If you're editing in professional software like Adobe Premiere, the `srt` format would integrate more seamlessly with your workflow.
## Implementation Example: Bringing It All Together
Let's walk through a complete example of how you might implement transcript retrieval in your application. This Python code sample demonstrates the process from request to application:
```python [expandable] theme={null}
import requests
import os
# Your authentication and identification details
API_KEY = "your_api_key_here"
RUN_ID = 12345
LANGUAGE = 1 # Language ID (e.g., `1` for English-United States)
# Set up your request parameters
url = f"https://client.camb.ai/apis/transcript/{RUN_ID}/{LANGUAGE}"
headers = {"x-api-key": API_KEY}
params = {
"format_type": "vtt", # Choosing WebVTT for web video integration
"data_type": "file" # Getting a downloadable file
}
# Make the request to the Camb.ai API
response = requests.get(url, headers=headers, params=params)
# Process the response based on its status
if response.status_code == 200:
if params["data_type"] == "file":
# Extract the file URL from the response
file_url = response.json()["transcript"]
print(f"Success! Transcript file available at: {file_url}")
# Download the transcript file to your local environment
transcript_response = requests.get(file_url)
# Save the file with appropriate naming
filename = f"transcript_{RUN_ID}_{LANGUAGE}.{params['format_type']}"
with open(filename, "wb") as f:
f.write(transcript_response.content)
print(f"Transcript downloaded and saved as {filename}")
else:
# For direct content, the transcript text is under the "transcript" key
transcript = response.json()["transcript"]
print("Transcript content retrieved successfully:")
# Here you might process the text further, such as:
# - Storing in a database
# - Analyzing for keywords
# - Displaying in your application interface
# For this example, we'll just show the first 150 characters
preview = transcript[:150] + "..." if len(transcript) > 150 else transcript
print(f"Preview: {preview}")
else:
# Handle any errors that might occur
print(f"Error {response.status_code}: Could not retrieve transcript")
print(f"Details: {response.text}")
```
This code not only retrieves your transcript but also demonstrates proper error handling and different processing paths based on your chosen response type. Notice how we create a meaningful filename that includes both the run ID and language - this kind of attention to detail helps keep your transcripts organized when working with multiple videos or languages.
## Building a Complete Workflow
The transcript endpoint works best as part of a complete content processing workflow. Consider how it connects with these related endpoints:
* [Create Dubbing Run](end-to-end-dubbing) - Start the process by submitting your video for dubbing
* [Check Dubbing Status](get-end-to-end-dubbing-status) - Monitor progress and determine when your transcript will be available
* [Get Dubbed Media](get-dubbed-run-info) - Retrieve the dubbed media that corresponds to your transcript
By combining these endpoints, you can create powerful automation workflows that transform, translate, and repurpose your content with minimal manual intervention.
# Get Dubbing Result
Source: https://docs.camb.ai/api-reference/endpoint/get-dubbed-run-info
get /dub-result/{run_id}
Retrieves the result of a specific end to end dubbing run using the provided `run_id`.
Retrieve the completed results of your dubbing process with this endpoint. Once your dubbing task has finished processing, this API call provides access to the final dubbed media files along with a detailed transcript of the content. This allows you to seamlessly integrate the dubbed content into your applications, content management systems, or distribution platforms without requiring additional processing.
## Understanding Dubbing Results
When you request the results of a completed dubbing task, our system returns a comprehensive package including:
* **Dubbed Video**: A complete video file with the original visuals and newly generated voiceover in your target language.
* **Dubbed Audio**: An isolated audio track containing only the synthesized speech in your target language.
* **Complete Transcript**: A detailed, time-coded transcript of the dubbed content with speaker identification.
This multi-format approach gives you flexibility in how you utilize and distribute your newly localized content across various platforms and use cases.
## Accessing You Dubbed content
To retrieve your dubbing results, you'll need the `run_id` that was provided when during the polling of your dubbing task. This identifier uniquely tracks your specific dubbing task through our processing pipeline.
### Example Request with Python
Here's how to fetch your completed dubbing results using Python:
```python [expandable] theme={null}
import requests
import json
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def get_dubbing_result(run_id):
"""
Retrieves the complete results of a finished dubbing task.
Returns URLs to the final media files and a detailed transcript.
"""
try:
response = requests.get(
f"https://client.camb.ai/apis/dub-result/{run_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Extract the dubbing results
result_data = response.json()
print(f"Successfully retrieved dubbing results for Run ID: {run_id}")
print(f"Video URL: {result_data['output_video_url']}")
print(f"Audio URL: {result_data['output_audio_url']}")
print(f"Transcript contains {len(result_data['transcript'])} dialogue entries")
return result_data
except requests.exceptions.RequestException as e:
print(f"Error retrieving dubbing results: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
run_id = 12345 # Replace with your actual `run_id` from the dubbing request
dubbing_results = get_dubbing_result(run_id)
# Process the transcript if results were successfully retrieved
if dubbing_results and 'transcript' in dubbing_results:
print("\nTranscript Preview:")
for i, dialogue in enumerate(dubbing_results['transcript'][:3]): # Show first 3 entries
print(f"Speaker {dialogue['speaker']}: {dialogue['text']} [{dialogue['start']} - {dialogue['end']}]")
if len(dubbing_results['transcript']) > 3:
print("... and more dialogue entries")
```
# Get End to End Dubbing Task Status
Source: https://docs.camb.ai/api-reference/endpoint/get-end-to-end-dubbing-status
get /dub/{task_id}
Retrieves the current status of a Dubbing task using the specified `task_id`.
Monitor the progress of your dubbing tasks with our status tracking endpoint. This essential companion to our dubbing service lets you check on your media transformation in real-time, providing detailed information about which stage of the process your content has reached. By polling this endpoint, you can keep track of your dubbing tasks progress and detect any issues that might arise during processing.
This endpoint works in conjunction with the main [`/dub`](end-to-end-dubbing) endpoint, which initiates the dubbing process and provides the `task_id` needed for status checks.
## Implementing Status Checking
Here's how to implement status checking in your application using Python:
```python [expandable] theme={null}
import requests
import json
import time
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def check_dubbing_status(task_id):
"""
Polls the status endpoint to track a dubbing task's progress.
Continues checking until the task reaches a terminal state.
"""
if not task_id:
print("Error: No task ID provided")
return None
terminal_states = ["SUCCESS", "ERROR"]
current_status = None
while current_status not in terminal_states:
try:
# Make the status request
response = requests.get(
f"https://client.camb.ai/apis/dub/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Extract the status information
status_data = response.json()
current_status = status_data.get("status")
# Display current progress information
print(f"Status: {current_status}")
if current_status == "PENDING":
time.sleep(15)
continue
# Handle completed state
if current_status == "SUCCESS":
print("Dubbing task completed successfully!")
return status_data
# Handle failed state
if current_status == "ERROR":
print(f"Dubbing task failed: {status_data.get('message')}")
return status_data
# Wait before next check to avoid excessive requests
time.sleep(30) # Poll every 30 seconds
except requests.exceptions.RequestException as e:
print(f"Error checking dubbing status: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
return None
# Example usage with a task_id from a previous dubbing request
task_id = "your_task_id" # Replace with your actual task ID
final_status = check_dubbing_status(task_id)
```
## Best Practices for Status Monitoring
To efficiently track your dubbing tasks, consider these professional recommendations:
1. **Implement Exponential Backoff**: Start with frequent checks that gradually increase in interval to avoid overloading the API.
2. **Handle Terminal States**: Always implement proper handling for both successful completion and failure cases.
By properly integrating status checking into your application, you can create a seamless dubbing experience that keeps your users informed throughout the entire process.
# Get Project Setup Result
Source: https://docs.camb.ai/api-reference/endpoint/get-project-setup-run-result
get /project-setup-result/{run_id}
Retrieves the comprehensive results of a completed project setup process, providing detailed information about your prepared project and its readiness for editing in CAMB.AI Studio.
Access the complete details of your finished project setup with this essential endpoint. Once your project setup task has completed its preparation process, this API call delivers comprehensive information about your newly configured project, including all the analysis results, configuration details, and metadata that make your content ready for creative editing in CAMB.AI Studio. Think of this as receiving your project's complete preparation report, telling you everything the system discovered and configured during the setup process.
## Understanding Project Setup Results
When you request the results of a completed project setup task, the system returns a comprehensive package that serves multiple important purposes in your content workflow. The response contains detailed information about your project's current state, the analysis results that informed the setup process, and the configuration parameters that will guide editing work in CAMB.AI Studio.
The run details section provides the foundational information that helps teams coordinate their work effectively. This includes the descriptive information you provided during setup, such as the project name and description that help identify and contextualize the work. You'll also find timing information that tracks when the project was created, which proves valuable for project management and workflow coordination. The language configuration details confirm exactly which source and target languages were configured, ensuring that everyone understands the scope of the localization work ahead.
## Accessing Your Project Setup Results
To retrieve your project setup results, you'll need the `run_id` that becomes available once your project setup task has completed successfully. This identifier serves as your unique key to access all the detailed information about your prepared project. Think of the `run_id` as your project's passport, providing access to everything the system learned and configured during the preparation process.
### Example Request with Python
Here's how to retrieve your completed project setup results using Python, with detailed explanations of what each part of the process accomplishes:
```python [expandable] theme={null}
import requests
import json
from datetime import datetime
# Configure authentication headers for API access
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json",
}
def get_project_setup_result(run_id):
"""
Retrieves the comprehensive results of a finished project setup task.
This function accesses all the detailed information about your prepared project,
including analysis results and configuration details that inform Studio editing.
The returned data provides everything your creative team needs to understand
the project structure and begin effective editing work.
"""
try:
# Make the API request to retrieve setup results
response = requests.get(
f"https://client.camb.ai/apis/project-setup-result/{run_id}",
headers=headers,
)
# Verify that the request completed successfully
response.raise_for_status()
# Parse the comprehensive project setup results
result_data = response.json()
# Extract key project information for workflow coordination
run_details = result_data.get("run_details")
return run_details
except requests.exceptions.RequestException as e:
print(f"Error retrieving project setup results: {e}")
if hasattr(e, "response") and e.response is not None:
print(f"Response content: {e.response.text}")
return None
# Replace with your actual run_id from the completed setup task
run_id = 12345
project_results = get_project_setup_result(run_id)
# Process and display detailed project information if results were retrieved successfully
if project_results:
project_name = project_results.get("project_name", "Unnamed Project")
description = project_results.get("project_description")
creation_time = project_results.get("created_at")
duration = project_results.get("duration")
source_language = project_results.get("source_language")
target_languages = project_results.get("target_languages", [])
studio_url = project_results.get("studio_url", None)
print("\n--- Detailed Project Analysis ---")
print(f"Run ID: {run_id}")
print(f"Successfully retrieved setup results for: {project_name}")
# Show project description for context understanding
if description:
print(f"Project description: {description}")
# Display timing information for project management
if creation_time:
# Convert ISO timestamp to readable format for team coordination
created = datetime.fromisoformat(creation_time.replace("Z", "+00:00"))
print(f"Project created: {created.strftime('%Y-%m-%d %H:%M:%S UTC')}")
# Display duration information for resource planning
if duration:
# Convert seconds to minutes and seconds for easier understanding
minutes = int(duration // 60)
seconds = int(duration % 60)
print(f"Media duration: {minutes}m {seconds}s ({duration:.1f} seconds)")
# Display organizational information for team coordination
if team_id:
print(f"Team ID: {team_id}")
# Show language configuration that determines dubbing scope
print(f"Source language: {source_language}")
# Show target language details for localization planning
print(f"Target languages: {len(target_languages)} configured")
print("This project will create dubbed versions in each configured language")
print("\nProject is ready for creative editing in CAMB.AI Studio")
if studio_url:
print(f"Your team can now access this project to begin detailed dubbing work using this URL: {studio_url}")
```
## Planning Your Next Steps
Understanding your project setup results helps you make informed decisions about the creative editing phase that follows. The information provides essential context for planning editing time, coordinating team resources, and setting realistic expectations for project completion.
The duration and complexity information helps you estimate how much creative editing time will be required to achieve your quality goals. Projects with longer duration or more complex audio structures typically require more detailed attention during the editing process, while simpler projects might progress more quickly through creative refinement.
The language configuration details help you plan resource allocation across different target languages, particularly when working with languages that have different characteristics or when your team has varying expertise across different languages. Understanding the full scope of language work ahead enables better planning for review processes and quality assurance approaches.
# Get Project Setup Task Status
Source: https://docs.camb.ai/api-reference/endpoint/get-project-setup-status
get /project-setup/{task_id}
Monitor the progress and completion status of your project setup tasks. This endpoint provides real-time insights into the preparation process, helping you understand when your project becomes ready for editing in CAMB.AI Studio.
Understanding the status of your project setup process is crucial for coordinating workflows between technical teams and creative editors. This endpoint transforms the uncertainty of background processing into clear, actionable information about your project's readiness for Studio editing. Think of it as your project's progress dashboard, providing the visibility needed to plan next steps and coordinate team handoffs effectively.
When you initiate a project setup through the API, the system begins a sophisticated analysis and preparation process that happens behind the scenes. Rather than leaving you wondering about progress, this status endpoint provides detailed insights into each stage of preparation, helping you understand not just whether your project is ready, but what specific work has been completed and what remains in progress.
## Understanding Project Setup Progress
Project setup involves multiple complex operations that must complete successfully before your project becomes available in CAMB.AI Studio. Each operation contributes essential components to the final project workspace, and understanding this progression helps you better coordinate your content workflows.
The setup process begins with comprehensive media analysis, where our system examines your source content to understand its characteristics, audio structure, and optimal processing parameters. This analysis phase determines how the system will approach transcription, translation, and voice synthesis for your specific content. The status endpoint reveals insights from this analysis, helping you understand what the system discovered about your media and how it plans to optimize the dubbing process.
## The Task ID Connection
The task ID serves as your unique identifier for tracking project setup progress from initiation through completion. This identifier creates a direct link between your API-initiated project and the resulting Studio workspace, enabling seamless coordination between technical and creative workflows.
When you submit a project setup request, the system immediately returns a task ID that becomes your tracking reference throughout the preparation process. This ID remains constant and unique, allowing you to query status information at any time without ambiguity about which project you're monitoring. The same task ID that tracks setup progress will also identify your project within CAMB.AI Studio once preparation complete
## Monitoring Implementation
Let's examine how to effectively monitor project setup progress using Python. This implementation demonstrates both basic status checking and more sophisticated monitoring patterns that integrate well with broader workflow automation.
```python [expandable] theme={null}
import requests
import json
import time
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def check_project_setup_status(task_id):
"""
Polls the status endpoint to track a project setup task's progress.
Continues checking until the task reaches a terminal state.
"""
if not task_id:
print("Error: No task ID provided")
return None
terminal_states = ["SUCCESS", "ERROR"]
current_status = None
while current_status not in terminal_states:
try:
# Make the status request
response = requests.get(
f"https://client.camb.ai/apis/project-setup/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Extract the status information
status_data = response.json()
current_status = status_data.get("status")
# Display current progress information
print(f"Status: {current_status}")
if current_status == "PENDING":
time.sleep(15)
continue
# Handle completed state
if current_status == "SUCCESS":
print("Project setup completed successfully!")
return status_data
# Handle failed state
if current_status == "ERROR":
print(f"Project setup task failed: {status_data.get('message')}")
return status_data
# Wait before next check to avoid excessive requests
time.sleep(30) # Poll every 30 seconds
except requests.exceptions.RequestException as e:
print(f"Error checking project setup status: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
return None
# Example usage with a task_id from a previous dubbing request
task_id = "your_task_id" # Replace with your actual task ID
final_status = check_project_setup_status(task_id)
print(f"Project Setup Task Status: {final_status}")
```
## Best Practices for Status Monitoring
To efficiently track your project setup tasks, consider these professional recommendations:
1. Implement Exponential Backoff: Start with frequent checks that gradually increase in interval to avoid overloading the API.
2. Handle Terminal States: Always implement proper handling for both successful completion and failure cases.
By properly integrating status checking into your application, you can create a seamless dubbing experience that keeps your users informed throughout the entire process.
# Get all Source Languages
Source: https://docs.camb.ai/api-reference/endpoint/get-source-languages
get /source-languages
Retrieves a comprehensive list of all source languages supported by the platform, including their unique identifiers, language names, and corresponding short names.
This endpoint serves as your gateway to the multilingual capabilities of our platform, providing a complete catalog of all languages that can be used as source languages in translation, text-to-speech, and other language processing operations. By querying this endpoint, you'll receive detailed information about each supported language, enabling you to make informed choices when implementing multilingual features in your applications.
## Understanding Source Languages
Source languages represent the starting point in language transformation processes. When you translate content, convert text to speech, or perform other language operations, the source language is the original language of your content. Having accurate information about available source languages is fundamental to ensuring your application correctly processes user input.
## How to Use This Endpoint
To retrieve the list of supported source languages, simply send a `GET` request to this endpoint. No parameters are required, as the response will include all available source languages. The system will respond with an array containing detailed information about each language.
## Understanding Language Identifiers
The language identifiers returned by this endpoint are crucial for other API operations. When you make requests to endpoints like [`/translate`](create-translation), [`/tts`](create-tts), or other language-processing endpoints, you'll need to specify the source language using the `id` value. This creates a consistent system for language identification across the entire API.
Here's how the language identifiers connect different parts of the API ecosystem:
1. **Fetch available languages** using the [`/source-languages`](get-source-languages) endpoint.
2. **Present choices** to your users in a meaningful way using the `language` property.
3. **Submit requests** to other endpoints using the `id` property as the language identifier.
This workflow ensures that your application always uses valid language values that the API can understand and process correctly.
## Relationship with Target Languages
It's important to understand the distinction between source languages (provided by this endpoint) and target languages (provided by the [`/target-languages`](get-target-languages) endpoint):
* **Source languages** are languages that your content starts in.
* **Target languages** are languages that your content can be translated into.
While there is often significant overlap between these sets, they are not always identical. Some languages may be available as source languages but not as target languages, or vice versa. For comprehensive multilingual applications, you should check both endpoints to understand the full range of language transformations available to you.
## Best Practices
When working with the `/source-languages` endpoint, consider these recommendations:
1. **Cache the results**: Since language lists change infrequently, store the response locally and refresh it periodically (e.g., once a day) rather than making a request every time a user interacts with your application.
2. **Sort languages appropriately**: In user interfaces, consider sorting languages alphabetically or by relevance to your user base.
3. **Use appropriate identifiers**: Always use the `id` field when making API requests, rather than the language name or short name.
4. **Provide search functionality**: For applications with many language options, implement search or filtering to help users quickly find their desired language.
5. **Consider language variants**: Be aware that some languages may have multiple variants (e.g., American English vs. British English) that could be listed separately.
By leveraging this endpoint effectively, you can create truly global applications that serve users in their preferred languages, enhancing accessibility and user experience across diverse audiences.
# Retrieve Story Results
Source: https://docs.camb.ai/api-reference/endpoint/get-story-run-info
get /story-result/{run_id}
Access completed story conversion outputs and transcripts using the unique run identifier
Obtain the final products of your story conversion process through this endpoint. When a story generation task completes successfully, this endpoint provides direct access to the produced audio files and optional textual transcript - enabling immediate integration into audiobook platforms, content management systems, or interactive storytelling applications.
## Story Conversion Outputs
Successful requests return three core components:
* **Full Audio Narration**: Complete audiobook-style recording (`audio_url`)
* **Dialogue-Only Track**: Isolated character conversations (`dialogue_url`)
* **Time-Coded Transcript**: Optional narrative transcript with speaker attribution
Transcripts require explicit request via the `include_transcript` query parameter
Retrieved audio links become inaccessible after 24 hours
## Example Python Implementation
Here’s how to fetch your completed story results using Python:
```python [expandable] theme={null}
import requests
def fetch_story_assets(run_id, include_transcript=False):
"""
Retrieves story conversion outputs with optional transcript
Args:
run_id: Unique identifier from story processing task
include_transcript: Whether to return narrative transcript
Returns:
Dict containing audio URLs and optional transcript
"""
headers = {
"x-api-key": "your-api-key",
"Content-Type": "application/json"
}
params = {"include_transcript": str(include_transcript).lower()}
try:
response = requests.get(
f"https://client.camb.ai/apis/story-result/{run_id}",
headers=headers,
params=params
)
response.raise_for_status()
result = response.json()
print(f"Retrieved story assets for Run ID: {run_id}")
return result
except requests.exceptions.HTTPError as e:
print(f"Error {e.response.status_code}: {e.response.text}")
return None
# Example usage with transcript request
story_data = fetch_story_assets(
run_id=9872, # Replace with your actual run ID.
include_transcript=True
)
if story_data:
print(f"Main Audio: {story_data['audio_url']}")
print(f"Dialogue Track: {story_data['dialogue_url']}")
if story_data.get('transcript'):
print(f"\nTranscript Preview:")
for entry in story_data['transcript'][:2]:
print(f"[{entry['start']}-{entry['end']}ms] {entry['speaker']}: {entry['text']}")
```
# Get Story Task Status
Source: https://docs.camb.ai/api-reference/endpoint/get-story-status
get /story/{task_id}
Retrieves the current status of a story task using the specified `task_id`.
Track the progression of your story creation process through systematic status checks. This endpoint provides granular visibility into each processing stage, enabling precise workflow management for time-sensitive applications.
This endpoint works in conjunction with the main [`/story`](create-story) endpoint, which initiates the dubbing process and provides the `task_id` needed for status checks.
## Checking Your Story Status
Let's explore how to effectively monitor your generation task using Python:
```python [expandable] theme={null}
import requests
import time
import json
from datetime import datetime
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def check_story_status(task_id, polling_interval=5):
"""
Monitors the status of a story generation task until completion.
Parameters:
- task_id: The unique identifier for your generation task
- polling_interval: How frequently to check status (in seconds)
Returns:
- The final status response upon completion or failure
"""
print(f"Beginning status monitoring for task: {task_id}")
# Initialize tracking variables
start_time = datetime.now()
last_status = None
while True:
try:
# Request the current status
response = requests.get(
f"https://client.camb.ai/apis/story/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Parse the status information
status_data = response.json()
current_status = status_data.get('status')
# Track status changes for informative updates
if current_status != last_status:
elapsed_time = (datetime.now() - start_time).total_seconds()
print(f"[{elapsed_time:.1f}s] Status: {current_status}")
# Update our tracking variables
last_status = current_status
last_substatus = current_substatus
# Check if the process has completed or failed
if current_status == "SUCCESS":
print("\n✓ Sound generation completed successfully!")
print(f"Run ID : {status_data.get('run_id')}")
return status_data
elif current_status == "FAILED":
print(f"\n✗ Sound generation failed: {status_data.get('message', 'Unknown error')}")
return status_data
# Wait before checking again
time.sleep(polling_interval)
except requests.exceptions.RequestException as e:
print(f"Error checking generation status: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
# Brief pause before retry after error
time.sleep(polling_interval)
# Example usage with intelligent polling
task_id = "your_task_id" # Replace with your actual task_id
final_status = check_story_status(task_id, polling_interval=3)
# Process the completed result
if final_status and final_status.get('status') == "SUCCESS":
print(f"Processing completed audio from: {audio_url}")
# Download the generated audio
audio_response = requests.get(audio_url)
if audio_response.status_code == 200:
print(f"Task completed successfully!, run ID {status_data.get('run_id')}")
```
## Best Practices for Status Monitoring
To efficiently track your dubbing tasks, consider these professional recommendations:
1. **Implement Exponential Backoff**: Start with frequent checks that gradually increase in interval to avoid overloading the API.
2. **Handle Terminal States**: Always implement proper handling for both successful completion and failure cases.
By properly integrating status checking into your application, you can create a seamless dubbing experience that keeps your users informed throughout the entire process.
# Get Subtitle Result for Language
Source: https://docs.camb.ai/api-reference/endpoint/get-subtitle-result-for-language
get /sub-result/{run_id}/{language}
Retrieves the transcript in a specific language of a completed subtitle run using the provided `run_id`, with optional export to `srt`/`vtt`/`txt`.
Fetches subtitles for **one language** of a completed subtitle run.
* **By default** (no query params) you get the **structured JSON transcript** for that language: `{ "transcript": [ {start, end, text, speaker}, ... ] }`.
* **When you pass `format_type` and/or `data_type`**, the transcript is exported and returned as `{ "transcript": }`, the same parameter values and response shape as [Get Transcription Result](get-transcription-run-result).
The `{language}` path parameter must be the run's source language or one of the target languages from [Create Subtitle](create-subtitle). Pass a locale tag (`es-es`, `fr-fr`); numeric IDs still work but are deprecated.
If the run was created with `formatting_options` on [Create Subtitle](create-subtitle), the segments already follow subtitle timing and length rules.
## Choosing your output
| Parameter | Values | Behaviour |
| :------------------- | :------------------------------------------------------ | :----------------------------------------------------------------------------------- |
| *(none)* | n/a | Structured JSON transcript: `{ "transcript": [ {start, end, text, speaker}, ... ] }` |
| `data_type=file` | `srt` / `vtt` / `txt` via `format_type` (default `txt`) | `{ "transcript": "" }`: a downloadable file |
| `data_type=raw_data` | `srt` / `vtt` / `txt` via `format_type` (default `txt`) | `{ "transcript": "" }`: the rendered text inline |
`format_type` (`srt`/`vtt`/`txt`) and `data_type` (`raw_data`/`file`) use the exact same values as [Get Transcription Result](get-transcription-run-result). Need every language at once? Use [Get Subtitle Result](get-subtitle-run-result) — it supports the same export params for all languages in one call.
## Implementation Example
```python [expandable] theme={null}
import requests
API_KEY = "your_api_key_here"
RUN_ID = 12345
LANGUAGE = "es-es" # Locale tag; numeric IDs (e.g. 23) still work but are deprecated
url = f"https://client.camb.ai/apis/sub-result/{RUN_ID}/{LANGUAGE}"
headers = {"x-api-key": API_KEY}
# 1) Default: structured JSON transcript for this language
result = requests.get(url, headers=headers).json()
for segment in result["transcript"]:
print(f"[{segment['start']} - {segment['end']}] {segment['speaker']}: {segment['text']}")
# 2) Export: presigned URL to an SRT file
srt = requests.get(
url, headers=headers, params={"format_type": "srt", "data_type": "file"}
).json()
print(f"SRT file: {srt['transcript']}")
# 3) Export: raw VTT text inline
vtt = requests.get(
url, headers=headers, params={"format_type": "vtt", "data_type": "raw_data"}
).json()
print(vtt["transcript"][:150])
```
## Understanding the Response Structure
The response is always a JSON object with a single `transcript` field. Its value depends on the parameters.
### Default: structured transcript (no params)
```json theme={null}
{
"transcript": [
{ "start": 5.0, "end": 12.0, "text": "Bienvenidos a nuestra discusión sobre IA.", "speaker": "SPEAKER_0" },
{ "start": 13.0, "end": 18.0, "text": "Gracias por invitarme.", "speaker": "SPEAKER_1" }
]
}
```
| Field | Description |
| :-------- | :------------------------------------- |
| `start` | Start time of the segment (seconds) |
| `end` | End time of the segment (seconds) |
| `text` | Text for the segment, in that language |
| `speaker` | Speaker identifier |
### Export: file (`data_type=file`)
```json theme={null}
{ "transcript": "https://storage.example.com/.../output_transcript.srt?..." }
```
`transcript` is a presigned URL to the rendered file. The file content matches your `format_type`:
#### TXT (`format_type=txt`)
```
[00:00:05 - 00:00:12] SPEAKER_0: Bienvenidos a nuestra discusión sobre IA.
[00:00:13 - 00:00:18] SPEAKER_1: Gracias por invitarme.
```
#### SRT (`format_type=srt`)
```
1
00:00:05,000 --> 00:00:12,000
SPEAKER_0: Bienvenidos a nuestra discusión sobre IA.
2
00:00:13,000 --> 00:00:18,000
SPEAKER_1: Gracias por invitarme.
```
#### VTT (`format_type=vtt`)
```
WEBVTT
00:00:05.000 --> 00:00:12.000
SPEAKER_0: Bienvenidos a nuestra discusión sobre IA.
00:00:13.000 --> 00:00:18.000
SPEAKER_1: Gracias por invitarme.
```
### Export: raw data (`data_type=raw_data`)
The same rendered content is returned inline as a string:
```json theme={null}
{ "transcript": "1\n00:00:05,000 --> 00:00:12,000\nSPEAKER_0: Bienvenidos a nuestra discusión sobre IA.\n\n..." }
```
The presigned file URL expires after 24 hours, so download your file soon.
## Building a Complete Workflow
* [Create Subtitle](create-subtitle): submit your media for subtitle generation
* [Get Subtitle Task Status](poll-subtitle-result): determine when your subtitles are ready
* [Get Subtitle Result](get-subtitle-run-result): every language at once (same export params)
# Get Subtitle Result
Source: https://docs.camb.ai/api-reference/endpoint/get-subtitle-run-result
get /sub-result/{run_id}
Retrieves the transcript of a subtitle run using the provided `run_id`, for every language on the run.
Fetches the result of a completed subtitle run: the source language plus each target language from [Create Subtitle](create-subtitle).
* **By default** (no query params) you get the **structured JSON transcript**: one language returns `{ "transcript": [ {start, end, text, speaker}, ... ] }`; multiple languages return an object keyed by language ID with that same shape per language.
* **When you pass `format_type` and/or `data_type`**, every language on the run is exported. One language returns `{ "transcript": }`; multiple languages return an object keyed by language ID, each value `{ "transcript": }`. Same parameter values as [Get Transcription Result](get-transcription-run-result).
Use the `run_id` returned when you created the subtitle run. The run must have finished processing and must be a subtitle project.
If the run was created with `formatting_options` on [Create Subtitle](create-subtitle), every language's segments already follow subtitle timing and length rules. The response shape stays the same; only where each segment starts and ends differs.
## Choosing your output
| Parameter | Values | Behaviour |
| :------------------- | :------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------- |
| *(none)* | n/a | Structured JSON: one language → `{ "transcript": [ ... ] }`; many → `{ "": { "transcript": [ ... ] }, ... }` |
| `data_type=file` | `srt` / `vtt` / `txt` via `format_type` (default `txt`) | One language → `{ "transcript": "" }`; many → `{ "": { "transcript": "" }, ... }` |
| `data_type=raw_data` | `srt` / `vtt` / `txt` via `format_type` (default `txt`) | Same shapes as `file`, but each `transcript` value is the rendered text inline |
`format_type` (`srt`/`vtt`/`txt`) and `data_type` (`raw_data`/`file`) use the exact same values as [Get Transcription Result](get-transcription-run-result). For a single language only, use [Get Subtitle Result for Language](get-subtitle-result-for-language).
## Implementation Example
```python [expandable] theme={null}
import requests
API_KEY = "your_api_key_here"
RUN_ID = 12345
url = f"https://client.camb.ai/apis/sub-result/{RUN_ID}"
headers = {"x-api-key": API_KEY}
# 1) Default: structured JSON for every language
result = requests.get(url, headers=headers).json()
if "transcript" in result:
for segment in result["transcript"]:
print(f"[{segment['start']} - {segment['end']}] {segment['speaker']}: {segment['text']}")
else:
for language_id, language_result in result.items():
print(f"\nLanguage {language_id}:")
for segment in language_result["transcript"]:
print(f" [{segment['start']} - {segment['end']}] {segment['speaker']}: {segment['text']}")
# 2) Export: SRT file URL for every language
srt = requests.get(
url, headers=headers, params={"format_type": "srt", "data_type": "file"}
).json()
if "transcript" in srt:
print(f"SRT file: {srt['transcript']}")
else:
for language_id, payload in srt.items():
print(f"Language {language_id}: {payload['transcript']}")
# 3) Export: raw VTT text inline for every language
vtt = requests.get(
url, headers=headers, params={"format_type": "vtt", "data_type": "raw_data"}
).json()
if "transcript" in vtt:
print(vtt["transcript"][:150])
else:
for language_id, payload in vtt.items():
print(f"Language {language_id}:\n{payload['transcript'][:150]}")
```
## Understanding the Response Structure
### Default: structured transcript (no params)
#### Single language on the run
```json theme={null}
{
"transcript": [
{ "start": 5.0, "end": 12.0, "text": "Welcome to our discussion on AI.", "speaker": "SPEAKER_0" },
{ "start": 13.0, "end": 18.0, "text": "Thank you for having me.", "speaker": "SPEAKER_1" }
]
}
```
#### Multiple languages on the run
```json [expandable] theme={null}
{
"1": {
"transcript": [
{ "start": 5.0, "end": 12.0, "text": "Welcome to our discussion on AI.", "speaker": "SPEAKER_0" }
]
},
"23": {
"transcript": [
{ "start": 5.0, "end": 12.5, "text": "Bienvenidos a nuestra discusión sobre IA.", "speaker": "SPEAKER_0" }
]
}
}
```
| Field | Description |
| :-------- | :------------------------------------- |
| `start` | Start time of the segment (seconds) |
| `end` | End time of the segment (seconds) |
| `text` | Text for the segment, in that language |
| `speaker` | Speaker identifier |
### Export: file (`data_type=file`)
#### Single language
```json theme={null}
{ "transcript": "https://storage.example.com/.../output_transcript.srt?..." }
```
#### Multiple languages
```json theme={null}
{
"1": { "transcript": "https://storage.example.com/.../en_us/output_transcript.srt?..." },
"23": { "transcript": "https://storage.example.com/.../es_es/output_transcript.srt?..." }
}
```
`transcript` is a presigned URL to the rendered file. The file content matches your `format_type`:
#### TXT (`format_type=txt`)
```
[00:00:05 - 00:00:12] SPEAKER_0: Welcome to our discussion on AI.
[00:00:13 - 00:00:18] SPEAKER_1: Thank you for having me.
```
#### SRT (`format_type=srt`)
```
1
00:00:05,000 --> 00:00:12,000
SPEAKER_0: Welcome to our discussion on AI.
2
00:00:13,000 --> 00:00:18,000
SPEAKER_1: Thank you for having me.
```
#### VTT (`format_type=vtt`)
```
WEBVTT
00:00:05.000 --> 00:00:12.000
SPEAKER_0: Welcome to our discussion on AI.
00:00:13.000 --> 00:00:18.000
SPEAKER_1: Thank you for having me.
```
### Export: raw data (`data_type=raw_data`)
The same rendered content is returned inline as a string (flat for one language, keyed by language ID for many):
```json theme={null}
{ "transcript": "1\n00:00:05,000 --> 00:00:12,000\nSPEAKER_0: Welcome to our discussion on AI.\n\n..." }
```
```json theme={null}
{
"1": { "transcript": "1\n00:00:05,000 --> 00:00:12,000\nSPEAKER_0: Welcome...\n\n..." },
"23": { "transcript": "1\n00:00:05,000 --> 00:00:12,500\nSPEAKER_0: Bienvenidos...\n\n..." }
}
```
The presigned file URL expires after 24 hours, so download your file soon.
## Fetching Multiple Runs at Once
Need subtitles for several runs? Use [Fetch Subtitle Run Results](fetch-subtitles-runs-results) (`POST /apis/sub-results`). It accepts the same optional `format_type` / `data_type` query params.
## Building a Complete Workflow
* [Create Subtitle](create-subtitle): submit your media for subtitle generation
* [Get Subtitle Task Status](poll-subtitle-result): determine when your subtitles are ready
# Get all Target Languages
Source: https://docs.camb.ai/api-reference/endpoint/get-target-languages
get /target-languages
Retrieves a comprehensive list of all target languages supported by the platform, including their unique identifiers, language names, and corresponding short names.
This endpoint serves as your gateway to the multilingual output capabilities of our platform, providing a complete catalog of all languages that can be used as target languages in translation, text-to-speech, and other language processing operations. By querying this endpoint, you'll receive detailed information about each supported language, enabling you to make informed choices when implementing multilingual features in your applications.
## Understanding Target Languages
Target languages represent the destination in language transformation processes. When you translate content, the target language is the language into which your content will be converted. Having accurate information about available target languages is fundamental to ensuring your application correctly delivers content to your diverse user base.
## How to Use This Endpoint
To retrieve the list of supported target languages, simply send a `GET` request to this endpoint. No parameters are required, as the response will include all available target languages. The system will respond with an array containing detailed information about each language.
## Understanding Language Identifiers
The language identifiers returned by this endpoint are crucial for other API operations. When you make requests to endpoints like [`/translate`](create-translation), you'll need to specify the target language using the `id` value. This creates a consistent system for language identification across the entire API.
Here's how the language identifiers connect different parts of the API ecosystem:
1. **Fetch available languages** using the [`/target-languages`](get-target-languages) endpoint.
2. **Present choices** to your users in a meaningful way using the `language` property.
3. **Submit requests** to other endpoints using the `id` property as the language identifier.
This workflow ensures that your application always uses valid language values that the API can understand and process correctly.
## Relationship with Source Languages
It's important to understand the distinction between target languages (provided by this endpoint) and source languages (provided by the [`/source-languages`](get-source-languages) endpoint):
* **Target languages** are languages that your content can be translated into.
* **Source languages** are languages that your content starts in.
While there is often significant overlap between these sets, they are not always identical. Some languages may be available as target languages but not as source languages, or vice versa. For comprehensive multilingual applications, you should check both endpoints to understand the full range of language transformations available to you.
## Best Practices
When working with the `/target-languages` endpoint, consider these recommendations:
1. **Cache the results**: Since language lists change infrequently, store the response locally and refresh it periodically (e.g., once a day) rather than making a request every time a user interacts with your application.
2. **Sort languages appropriately**: In user interfaces, consider sorting languages alphabetically or by relevance to your user base.
3. **Use appropriate identifiers**: Always use the `id` field when making API requests, rather than the language name or short name.
4. **Provide search functionality**: For applications with many language options, implement search or filtering to help users quickly find their desired language.
5. **Display language variants clearly**: When presenting language options to users, ensure variants of languages (e.g., Brazilian Portuguese vs. European Portuguese) are clearly distinguished.
By leveraging this endpoint effectively, you can create truly global applications that deliver content in users' preferred languages, enhancing accessibility and user experience across diverse audiences.
# Get Sound and Music Run Result
Source: https://docs.camb.ai/api-reference/endpoint/get-text-to-sound-run-result
get /text-to-sound-result/{run_id}
Retrieve the generated audio file for a completed Sound and Music task.
This endpoint retrieves the audio output generated from a previously completed Sound and Music task. It provides access to the audio content that was created based on the text prompt and configuration specified in your original request based on returned `run_id`.
The endpoint supports two different response formats based on your needs:
### Audio Stream (Default)
Returns the raw audio bytes of your generated sound effect in WAV format. This is ideal for:
* Direct playback in browser applications
* Immediately saving the audio to your local system
* Streaming the audio to users in real-time applications
### Download URL
**Content-Type: application/json**
Returns a JSON object containing a URL where the generated audio file can be downloaded:
```json theme={null}
{
"file_url": "https://storage.example.com/text-to-sound/your-generated-file.wav"
}
```
This option is useful when you prefer to:
* Defer the actual download to a later time
* Share the audio file with others via a link
* Implement custom download behavior in your application
## Example Usage
### Retrieving Audio as a Stream
```bash theme={null}
curl -X GET "https://client.camb.ai.com/text-to-sound-result/run_abc123" \
-H "x-api-key: YOUR_API_KEY" \
--output my_sound_effect.wav
```
### Retrieving a Download URL
```bash theme={null}
curl -X GET "https://client.camb.ai.com/text-to-sound-result/run_abc123" \
-H "x-api-key: YOUR_API_KEY"
```
Response:
```json theme={null}
{
"file_url": "https://storage.example.com/sounds/abc123.wav"
}
```
## Best Practices
To get the most from this endpoint:
1. **Check Task Status First**: Only request results for tasks that have completed successfully.
2. **Handle Audio Appropriately**: The returned WAV format is widely compatible but may need conversion for specific use cases.
3. **Download Promptly**: Temporary URLs may expire after a certain period, so download and store important files.
## Technical Considerations
* The generated audio files are delivered in WAV format which provides high quality but larger file sizes.
* If the specified `run_id` doesn't exist or hasn't completed processing, you'll receive an appropriate error response.
By integrating this endpoint with your audio production workflow, you can seamlessly access AI-generated sound effects created from text descriptions, enabling new creative possibilities for your projects.
# Get Sound and Music Task Status
Source: https://docs.camb.ai/api-reference/endpoint/get-text-to-sound-status
get /text-to-sound/{task_id}
Checks the current status of a sound and music generation task by querying with the provided `task_id`.
Monitor and track your audio generation journey with our intelligent status tracking system. This essential endpoint serves as your window into the text-to-sound conversion process, providing real-time insights into how your audio creation status. Understanding the status of your generation tasks allows you to build responsive applications that can adapt to the asynchronous nature of complex audio synthesis, creating smoother user experiences and more efficient resource management in your creative workflows.
## Checking Your Sound Generation Status
Let's explore how to effectively monitor your generation task using Python:
```python [expandable] theme={null}
import requests
import time
import json
from datetime import datetime
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def check_sound_generation_status(task_id, polling_interval=5):
"""
Monitors the status of a text-to-sound generation task until completion.
Parameters:
- task_id: The unique identifier for your generation task
- polling_interval: How frequently to check status (in seconds)
Returns:
- The final status response upon completion or failure
"""
print(f"Beginning status monitoring for task: {task_id}")
# Initialize tracking variables
start_time = datetime.now()
last_status = None
while True:
try:
# Request the current status
response = requests.get(
f"https://client.camb.ai/apis/text-to-sound/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Parse the status information
status_data = response.json()
current_status = status_data.get('status')
# Track status changes for informative updates
if current_status != last_status:
elapsed_time = (datetime.now() - start_time).total_seconds()
print(f"[{elapsed_time:.1f}s] Status: {current_status}")
# Update our tracking variables
last_status = current_status
last_substatus = current_substatus
# Check if the process has completed or failed
if current_status == "SUCCESS":
print("\n✓ Sound generation completed successfully!")
print(f"Run ID : {status_data.get('run_id')}")
return status_data
elif current_status == "FAILED":
print(f"\n✗ Sound generation failed: {status_data.get('message', 'Unknown error')}")
return status_data
# Wait before checking again
time.sleep(polling_interval)
except requests.exceptions.RequestException as e:
print(f"Error checking generation status: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
# Brief pause before retry after error
time.sleep(polling_interval)
# Example usage with intelligent polling
task_id = "your_task_id" # Replace with your actual task_id
final_status = check_sound_generation_status(task_id, polling_interval=3)
# Process the completed result
if final_status and final_status.get('status') == "SUCCESS":
print(f"Processing completed audio from: {audio_url}")
# Download the generated audio
audio_response = requests.get(audio_url)
if audio_response.status_code == 200:
print(f"Task completed successfully!, run ID {status_data.get('run_id')}")
```
# Get Voice from Description Result
Source: https://docs.camb.ai/api-reference/endpoint/get-text-to-voice-run-result
get /text-to-voice-result/{run_id}
Retrieve AI-generated voice interpretations and select your preferred vocal style from multiple audio options using `run_id`.
## Understanding Voice Generation Results
This endpoint provides access to the results of your voice generation request after processing has completed. When you submit a text description through the [`/text-to-voice`](create-text-to-voice) endpoint, our system analyzes your parameters and creates not just one, but two distinct voice interpretations based on your description. This approach gives you the opportunity to compare different vocal realizations and select the one that best matches your intended use case.
## How to Access Your Voice Interpretations
To retrieve your voice generation results, you'll need the `run_id` that was provided when you initially submitted your voice generation request. This identifier uniquely references your specific generation task and allows you to access its results once processing is complete.
The endpoint follows this structure:
```
GET /text-to-voice-result/{run_id}
```
Where `{run_id}` should be replaced with your actual run identifier. For example:
```
GET /text-to-voice-result/8827
```
## Understanding the Response
When you call this endpoint, the system returns a JSON object containing URLs to two audio previews. Both previews represent a different interpretation of your voice description, speaking the same text content you provided during submission. These previews have the following characteristics:
### Preview Variations Explained
1. **Preview 1: Primary Interpretation**
This first interpretation closely adheres to the core parameters of your description. It represents the system's primary understanding of your requested voice characteristics, focusing on the fundamental attributes you specified such as gender, age range, and basic tonal qualities.
2. **Preview 2: Nuanced Alternative**
The second interpretation explores alternative expressions of your description with modified pacing and emphasis patterns. This version might adjust factors like speaking rate, rhythmic patterns, and the relative emphasis placed on different syllables or words, creating a subtly different feel while still honoring your core description.
Each of these interpretations applies different:
* **Emotional cadence variations**: How emotional qualities rise and fall throughout the speech
* **Prosody adjustments**: Alterations in intonation patterns, rhythm, stress, and tonal qualities
* **Phonetic emphasis patterns**: Changes in how individual sounds are articulated and emphasized
These variations are carefully calibrated to give you meaningful choices rather than random alternatives. By comparing the two interpretations side by side, you can identify which vocal qualities best serve your specific needs.
## From Preview to Permanent Voice
The preview voices you receive are temporary by design, intended to help you evaluate different interpretations of your description. However, you can convert any preview you particularly like into a permanent custom voice that becomes available throughout our speech synthesis ecosystem.
### Creating a Permanent Voice Profile
The process of converting a preview into a permanent voice involves these key steps:
First, call this endpoint to access your two preview options and determine which one best meets your needs.
Once you've selected your preferred preview, you can use the [`/voices/create-custom-voice`](create-custom-voice) endpoint to establish a permanent voice profile based on that preview.
After creation, your new voice becomes available for use across all compatible speech synthesis services within our platform.
This workflow allows you to move from concept (your text description) to evaluation (the two previews) to implementation (your permanent custom voice) in a streamlined process.
## Implementation Example
The following Python code demonstrates how to retrieve your preview samples and convert your preferred option into a permanent custom voice:
```python [expandable] theme={null}
import requests
BASE_URL = "https://client.camb.ai/apis"
def create_voice_from_preview(run_id, preview_index=0):
"""
Converts temporary preview into permanent custom voice
This function performs a complete workflow:
1. Retrieves the specified preview audio using the run_id
2. Downloads the selected preview to a local file
3. Creates a permanent voice clone from this sample
Parameters:
run_id (int): The unique identifier of your voice generation task
preview_index (int): Which preview to use (0 or 1, corresponding to the two previews)
Returns:
dict: Response from the custom voice creation API
"""
# Retrieve preview URL from the results endpoint
preview_res = requests.get(f"{BASE_URL}/text-to-voice-result/{run_id}")
preview_url = preview_res.json()['previews'][preview_index]
# Download the selected audio sample to a local file
audio_file = requests.get(preview_url).content
with open("voice_sample.mp3", "wb") as f:
f.write(audio_file)
# Create a permanent custom voice using the downloaded sample
files = {'file': open('voice_sample.mp3', 'rb')}
data = {
'voice_name': 'My Campaign Voice', # Choose a descriptive name for your voice
'gender': 1, # Male (matches preview characteristics)
'age': 35 # Estimated vocal age
}
creation_res = requests.post(
f"{BASE_URL}/create-custom-voice",
files=files,
data=data,
headers={"x-api-key": API_KEY}
)
return creation_res.json()
# Example usage
voice_profile = create_voice_from_preview(run_id=8827, preview_index=1)
print(f"New voice ID: {voice_profile['voice_id']}")
```
## Best Practices for Voice Selection
When evaluating your preview options, consider these factors to make the most effective choice:
1. **Content context**: Different voices may be more suitable depending on whether your content is informational, narrative, promotional, or instructional.
2. **Audience expectations**: Consider what vocal qualities would resonate best with your target audience based on their demographic and psychographic characteristics.
3. **Brand alignment**: If the voice will represent your brand, assess which interpretation best embodies your brand personality and values.
4. **Emotional impact**: Listen for how each voice conveys emotional subtext and choose the one that elicits the desired emotional response.
5. **Technical qualities**: Consider practical aspects like clarity, intelligibility across different listening environments, and how well the voice handles specialized vocabulary.
By comparing your two preview options with these considerations in mind, you can select the voice interpretation that will most effectively serve your communication objectives.
To ensure the best experience, always verify that your voice generation task has completed successfully before attempting to access the results
By understanding the nuances of voice interpretation and making thoughtful selections from your preview options, you can establish voice profiles that authentically convey your message and connect with your audience.
# Get Voice from Description Task Status
Source: https://docs.camb.ai/api-reference/endpoint/get-text-to-voice-status
get /text-to-voice/{task_id}
Monitor the progress of your AI-generated voice creation through real-time status updates.
Track every stage of your voice generation process with millisecond precision. This endpoint provides real-time visibility into voice synthesis tasks, enabling seamless integration with time-sensitive applications like live narration systems and interactive voice interfaces.
This endpoint works in conjunction with the main `/text-to-voice` endpoint, which initiates the voice generation process and provides the essential `task_id` for status monitoring.
## Monitoring Your Voice Generation
Implement intelligent status tracking with this Python example:
```python [expandable] theme={null}
def monitor_voice_creation(task_id, poll_interval=5):
"""
Advanced status tracking with automatic recovery suggestions
"""
status_guidance = {
"SUCCESS": {"icon": "✅", "action": "download_voice"},
"PENDING": {"icon": "⏳", "action": "wait"},
"TIMEOUT": {"icon": "⏰", "action": "retry_or_contact"},
"ERROR": {"icon": "❌", "action": "review_inputs"},
"PAYMENT_REQUIRED": {"icon": "💳", "action": "add_credits"}
}
while True:
response = requests.get(f"/text-to-voice/{task_id}", headers=headers)
status_data = response.json()
current_status = status_data.get('status')
# Get status metadata
guidance = status_guidance.get(current_status, {})
print(f"{guidance.get('icon', 'ℹ️')} Status: {current_status}")
# Handle terminal states
if current_status in ["SUCCESS", "TIMEOUT", "ERROR", "PAYMENT_REQUIRED"]:
print(f"Error details: {status_data.get('message', 'Contact support')}")
print(f"Recommended action: {guidance.get('action', 'contact_support')}")
if current_status == "SUCCESS":
print(f"\n🎉 Voice generation completed!")
print(f"Production ID: {status_data.get('run_id')}")
return status_data
time.sleep(poll_interval)
```
This polling mechanism gives you flexibility to build applications that can provide real-time feedback to users about their voice from description creations. You can adjust the polling interval based on your specific needs, checking more frequently for time-sensitive applications or less frequently for background tasks.
## Next Steps
Once your task shows a status of `SUCCESS`, you’ll receive a `run_id` in the response. This `run_id` is your key to accessing the generated sample audio files for the voices. Take this identifier and use it with the [`/text-to-voice-result/{run_id}`](get-text-to-vocie-run-result) endpoint to download your the sample voices, select the one that matches your desired characteristics and put it to work in your application.
# Get Transcription Result
Source: https://docs.camb.ai/api-reference/endpoint/get-transcription-run-result
get /transcription-result/{run_id}
Retrieves the transcript of a transcription run using the provided `run_id`.
Fetches the result of a completed transcription run.
* **By default** (no query params) you get the **structured JSON transcript**: an object whose `transcript` field is an array of `{ start, end, text, speaker }` segments.
* **When you pass `format_type` and/or `data_type`**, the transcript is exported in the requested subtitle format and returned as `{ "transcript": }`, the same parameter values and response shape as the dubbing [Get Dubbing Transcript](get-dub-transcript) endpoint.
Use the `run_id` returned when you created the transcription run. The run must have finished processing and must be a transcription project.
## Choosing your output
| Parameter | Values | Behaviour |
| :------------------- | :------------------------------------------------------ | :----------------------------------------------------------------------------------- |
| *(none)* | n/a | Structured JSON transcript: `{ "transcript": [ {start, end, text, speaker}, ... ] }` |
| `data_type=file` | `srt` / `vtt` / `txt` via `format_type` (default `txt`) | `{ "transcript": "" }`: a downloadable file |
| `data_type=raw_data` | `srt` / `vtt` / `txt` via `format_type` (default `txt`) | `{ "transcript": "" }`: the rendered text inline |
`format_type` (`srt`/`vtt`/`txt`) and `data_type` (`raw_data`/`file`) use the exact same values as the dubbing `/transcript` endpoint, and the export responses are identical.
## Implementation Example
```python [expandable] theme={null}
import requests
API_KEY = "your_api_key_here"
RUN_ID = 12345
url = f"https://client.camb.ai/apis/transcription-result/{RUN_ID}"
headers = {"x-api-key": API_KEY}
# 1) Default: structured JSON transcript
result = requests.get(url, headers=headers).json()
for segment in result["transcript"]:
print(f"[{segment['start']} - {segment['end']}] {segment['speaker']}: {segment['text']}")
# 2) Export: presigned URL to an SRT file
srt = requests.get(
url, headers=headers, params={"format_type": "srt", "data_type": "file"}
).json()
file_url = srt["transcript"]
print(f"SRT file: {file_url}")
# 3) Export: raw VTT text inline
vtt = requests.get(
url, headers=headers, params={"format_type": "vtt", "data_type": "raw_data"}
).json()
print(vtt["transcript"][:150])
```
## Understanding the Response Structure
The response is always a JSON object with a single `transcript` field. Its value depends on the parameters.
### Default: structured transcript (no params)
```json theme={null}
{
"transcript": [
{ "start": 5.0, "end": 12.0, "text": "Welcome to our discussion on AI.", "speaker": "SPEAKER_0" },
{ "start": 13.0, "end": 18.0, "text": "Thank you for having me.", "speaker": "SPEAKER_1" }
]
}
```
| Field | Description |
| :-------- | :---------------------------------- |
| `start` | Start time of the segment (seconds) |
| `end` | End time of the segment (seconds) |
| `text` | Transcribed text for the segment |
| `speaker` | Speaker identifier |
### Export: file (`data_type=file`)
```json theme={null}
{ "transcript": "https://storage.example.com/.../output_transcript.srt?..." }
```
`transcript` is a presigned URL to the rendered file. The file content matches your `format_type`:
#### TXT (`format_type=txt`)
```
[00:00:05 - 00:00:12] Speaker 1: Welcome to our discussion on AI.
[00:00:13 - 00:00:18] Speaker 2: Thank you for having me.
```
#### SRT (`format_type=srt`)
```
1
00:00:05,000 --> 00:00:12,000
Speaker 1: Welcome to our discussion on AI.
2
00:00:13,000 --> 00:00:18,000
Speaker 2: Thank you for having me.
```
#### VTT (`format_type=vtt`)
```
WEBVTT
00:00:05.000 --> 00:00:12.000
Speaker 1: Welcome to our discussion on AI.
00:00:13.000 --> 00:00:18.000
Speaker 2: Thank you for having me.
```
### Export: raw data (`data_type=raw_data`)
The same rendered content is returned inline as a string:
```json theme={null}
{ "transcript": "1\n00:00:05,000 --> 00:00:12,000\nSpeaker 1: Welcome to our discussion on AI.\n\n..." }
```
The presigned file URL expires after 24 hours, so download your file soon.
## Fetching Multiple Runs at Once
Need transcripts for several runs? Use [Fetch Transcription Run Results](fetch-transcriptions-runs-results) (`POST /apis/transcription-results`). It returns the structured `{ start, end, text, speaker }` transcript per run and does not take `format_type` / `data_type`.
## Building a Complete Workflow
* [Create Transcription](create-transcription): submit your media for transcription
* [Poll Transcription Status](poll-transcription-result): determine when your transcript is ready
# Get Translated Story Result
Source: https://docs.camb.ai/api-reference/endpoint/get-translated-story-run-result
get /translated-story-result/{run_id}/{target_language}
Retrieves detailed results about a specific translated story using the provided `run_id` and `target_language` parameters.
Access the complete results of your story translation process with our comprehensive retrieval endpoint. This powerful interface delivers everything you need to utilize your newly translated content, including professionally synthesized audio, formatted dialogue text, and optional transcription data. The system provides these assets in a well-structured format that makes integration into your applications or content management systems straightforward and efficient.
## Accessing Your First Translated Story Results
Let's examine how to retrieve your completed translation using Python:
```python [expandable] theme={null}
import requests
import json
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def get_translation_result(run_id, target_language, include_transcript=False):
"""
Retrieves the complete results of a translated story including audio and text assets.
Parameters:
- run_id: The ID of the original story that was translated
- target_language: The language code of the target language used for translation
- include_transcript: Boolean indicating whether to include the detailed transcript (default: False)
Returns:
- A dictionary containing all available translation assets
"""
try:
# Build the request URL with optional query parameter
base_url = f"https://client.camb.ai/apis/translated-story-result/{run_id}/{target_language}"
if include_transcript:
url = f"{base_url}?include_transcript=true"
else:
url = base_url
# Request the translation results
response = requests.get(
url,
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Parse the result information
result_data = response.json()
# Display information about the retrieved assets
print("Translation assets successfully retrieved!")
print(f"Complete Story Audio: {result_data.get('audio_url')}")
print(f"Dialogue Audio: {result_data.get('dialogue_url')}")
# Check if transcript was requested and is available
if include_transcript and 'transcript' in result_data:
print(f"Transcript entries: {len(result_data.get('transcript'))} dialogue items")
return result_data
except requests.exceptions.RequestException as e:
print(f"Error retrieving translation results: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
# Example usage
run_id = 12345 # Replace with your actual `run_id`
target_language = "fr-fr" # Locale tag. Numeric IDs (e.g. 76) still work but are deprecated.
translation_result = get_translation_result(run_id, target_language, include_transcript=True)
```
## Integrating Translation Results into Your Workflow
Once you've retrieved your translation results, you can integrate them into your content pipeline in numerous ways:
```python [expandable] theme={null}
def process_translation_assets(result_data, run_id):
"""
Demonstrates common ways to process and utilize the translation assets.
Parameters:
- result_data: The dictionary returned from get_translation_result()
- run_id: The ID of the translation run for file naming
"""
if not result_data:
print("No translation data available to process.")
return
# Download the complete story audio file
if 'audio_url' in result_data:
audio_response = requests.get(result_data['audio_url'])
if audio_response.status_code == 200:
# Save the audio file locally
with open(f"translated_story_{run_id}.flac", 'wb') as f:
f.write(audio_response.content)
print("Complete story audio file downloaded successfully.")
# Download the dialogue audio file
if 'dialogue_url' in result_data:
dialogue_response = requests.get(result_data['dialogue_url'])
if dialogue_response.status_code == 200:
# Save the dialogue audio file locally
with open(f"dialogue_audio_{run_id}.flac", 'wb') as f:
f.write(dialogue_response.content)
print("Dialogue audio file downloaded successfully.")
# Process the transcript if available
if 'transcript' in result_data and result_data['transcript']:
# Example: Export the transcript as a formatted text file
with open(f"transcript_{run_id}.txt", 'w', encoding='utf-8') as f:
for dialogue_item in result_data['transcript']:
speaker = dialogue_item.get('speaker', 'Narrator')
text = dialogue_item.get('text', '')
f.write(f"{speaker}: {text}\n\n")
print("Transcript exported successfully.")
# Example: Count dialogue entries by speaker
speaker_counts = {}
for dialogue_item in result_data['transcript']:
speaker = dialogue_item.get('speaker', 'Narrator')
speaker_counts[speaker] = speaker_counts.get(speaker, 0) + 1
print("Dialogue distribution by speaker:")
for speaker, count in speaker_counts.items():
print(f" - {speaker}: {count} lines")
# Process the retrieved translation assets
run_id = 12345 # Use the same run_id from earlier
if translation_result:
process_translation_assets(translation_result, run_id)
```
## Best Practices for Optimal Results
To maximize the effectiveness of your translated story assets, consider these professional recommendations:
1. **Content Deployment Strategy**: Plan how you'll use both the complete story audio and the separated dialogue audio in your applications. The separate dialogue track enables more sophisticated audio mixing and dynamic content presentation.
2. **Transcript Processing**: When working with the transcript data, consider extracting specific dialogue segments for interactive applications or for creating synchronized subtitles for media players.
3. **Asset Archiving**: Implement a structured archiving system for your translated assets that preserves the relationships between audio files and transcript data across multiple languages.
4. **Quality Assessment**: Review a sample of the translated content against the original to ensure the translation maintains the intended tone and meaning of your story.
5. **Error Handling**: Implement robust error handling in your integration code to gracefully manage situations where certain assets might be temporarily unavailable.
# Get Translated Story Status
Source: https://docs.camb.ai/api-reference/endpoint/get-translated-story-status
get /translated-story/{task_id}
Retrieves the current status of a story translation task using the specified `task_id`.
Monitor the progress of your story translation tasks with our dedicated status tracking endpoint. This essential companion to our translation service lets you check on your story's transformation journey in real-time, providing detailed information about which stage of the process your content has reached. By polling this endpoint, you can keep track of your translation progress and detect any issues that might arise during processing.
This endpoint works in conjunction with the [`/translated-story/{run_id}`](create-translated-story) endpoint, which initiates the translation process and provides the `task_id` needed for status checks.
## Understanding the Translation Pipeline
When you request a story translation, your content moves through several processing stages before completion. The status endpoint provides visibility into this journey, allowing you to:
1. Confirm your translation request was successfully received and is being processed
2. Monitor the progress as your story moves through different translation stages
3. Identify when the translation is complete and ready for use
4. Quickly detect and respond to any issues that might occur during processing
Having this level of insight helps you integrate story translations into your applications more effectively, allowing you to provide accurate progress updates to your users and plan subsequent workflows accordingly.
## Implementing Status Checking
Here's how to implement status checking in your application using Python:
```python [expandable] theme={null}
import requests
import json
import time
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def check_translation_status(task_id):
"""
Polls the status endpoint to track a story translation task's progress.
Continues checking until the task reaches a terminal state.
Parameters:
- task_id: The unique identifier returned when the translation request was submitted
Returns:
- The final status data when a terminal state is reached, or None if an error occurs
"""
if not task_id:
print("Error: No task ID provided")
return None
# Define the possible final states of a translation task
terminal_states = ["SUCCESS", "ERROR", "TIMEOUT", "PAYMENT_REQUIRED"]
current_status = None
while current_status not in terminal_states:
try:
# Make the status request
response = requests.get(
f"https://client.camb.ai/apis/translated-story/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Extract the status information
status_data = response.json()
current_status = status_data.get("status")
# Display current progress information
print(f"Status: {current_status}")
# Handle different status states
if current_status == "SUCCESS":
print("Translation completed successfully!")
print(f"Translated story URL: {status_data.get('story_url')}")
return status_data
elif current_status == "ERROR":
print(f"Translation failed: {status_data.get('error_message')}")
return status_data
elif current_status == "TIMEOUT":
print("Translation process timed out")
return status_data
elif current_status == "PAYMENT_REQUIRED":
print("Additional payment is required to complete this translation")
return status_data
elif current_status == "PENDING":
# Task is still in progress, wait before checking again
print("Translation in progress...")
if status_data.get('progress'):
print(f"Progress: {status_data.get('progress')}%")
if status_data.get('current_stage'):
print(f"Current stage: {status_data.get('current_stage')}")
# Wait before next check to avoid excessive requests
time.sleep(30) # Poll every 30 seconds
else:
# Unexpected status, wait and try again
print(f"Received status: {current_status}")
time.sleep(30)
except requests.exceptions.RequestException as e:
print(f"Error checking translation status: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
return status_data
# Example usage with a task_id from a previous translation request
task_id = "your_task_id" # Replace with your actual task ID
final_status = check_translation_status(task_id)
```
## Best Practices for Status Monitoring
To efficiently track your translation tasks, consider these professional recommendations:
1. **Implement Exponential Backoff**: Start with frequent checks that gradually increase in interval to avoid overloading the API. For example, begin with a 5-second interval, then double it each time until you reach a maximum of 2 minutes between checks.
2. **Handle All Possible States**: Ensure your code properly handles each possible status response, including unexpected values. This makes your integration robust against future API enhancements.
3. **Set Reasonable Timeouts**: For longer stories, translation may take significant time. Implement appropriate overall timeout periods based on the typical length of your content.
4. **Persist Task IDs**: Store task IDs securely in your database so you can resume status checking even if your application restarts or a user returns later.
5. **Provide Meaningful Feedback**: Translate technical status information into user-friendly messages that set appropriate expectations about completion time and next steps.
## Troubleshooting Common Issues
If you encounter difficulties while checking translation status, consider these common solutions:
1. **Invalid Task ID**: Verify the task ID was correctly stored and passed to the status endpoint. Task IDs are case-sensitive and must be used exactly as provided.
2. **Authentication Problems**: Ensure your API key is valid and correctly included in the request headers.
3. **Network Connectivity**: Implement proper error handling for network issues that might interrupt status checking, including automatic retry logic.
4. **Unexpected Terminal States**: If a translation ends with an error status, examine the error message for specific issues that might be addressed in subsequent translation attempts.
By properly integrating status checking into your application, you can create a seamless translation experience that keeps your users informed throughout the entire process, building confidence in your service and ensuring the timely delivery of translated content.
# Get Translation Result
Source: https://docs.camb.ai/api-reference/endpoint/get-translation-run-result
get /translation-result/{run_id}
Retrieves the final translated texts from a completed translation task using the provided `run_id`.
This endpoint delivers the final product of your translation process: the translated texts themselves. Once your translation task has completed successfully and you've received a `run_id`, this endpoint allows you to retrieve the actual translations that were generated. Think of it as the pickup counter where you collect your finished translations after they've been processed.
## How to Use This Endpoint
To retrieve your translated texts, send a `GET` request to this endpoint with the `run_id` you received when your translation task was marked as completed. This `run_id` serves as your claim ticket for the finished translations. The system will respond with an array containing all your translated texts, preserving the same order as your original input.
## Understanding the Response
When you call this endpoint, you'll receive a response that includes your translated content:
* **`texts`**: An array of strings containing the translated output texts. Each item in this array corresponds to one of the original texts you submitted, maintaining the same order. This makes it easy to match translations with their original content.
The structure of the response follows this format:
```json theme={null}
{
"texts": [
"Your first translated text",
"Your second translated text",
"Your third translated text"
// ...and so on for all texts in your original request
]
}
```
This straightforward response structure makes it simple to integrate translations into your application workflows. You can directly map each translated text to its corresponding original text by using the same array indices.
## Working with Translation Results
There are several common patterns for handling translation results effectively:
### Direct Integration
For immediate use, you can simply extract the texts array and use the translations in your application:
```python [expandable] theme={null}
import requests
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
}
# The run_id from your completed translation task
run_id = 12345 # Replace with your actual run ID
# Retrieve the translations
response = requests.get(
f"https://client.camb.ai/apis/translation-result/{run_id}",
headers=headers
)
# Check if the request was successful
response.raise_for_status()
# Extract the translations
result_data = response.json()
translations = result_data["texts"]
# Use the translations in your application
for i, translation in enumerate(translations):
print(f"Translation {i+1}: {translation}")
```
### Parallel Display
For applications that need to show both original and translated text together, you can zip the arrays:
```python [expandable] theme={null}
# Assuming you've stored your original texts
original_texts = [
"This is the first sentence to translate.",
"Here is the second one.",
"And finally, the third sentence."
]
# And you've retrieved the translations as shown above
translations = result_data["texts"]
# Create parallel display
for original, translated in zip(original_texts, translations):
print("Original: " + original)
print("Translated: " + translated)
print("---")
```
### Saving to Database
For longer-term storage, you might want to save the translation results alongside their originals:
```python [expandable] theme={null}
import sqlite3
# Set up database connection (replace with your actual database logic)
conn = sqlite3.connect("translations.db")
cursor = conn.cursor()
# Create table if it doesn't exist
cursor.execute("""
CREATE TABLE IF NOT EXISTS translations (
id INTEGER PRIMARY KEY,
original_text TEXT,
translated_text TEXT,
source_language INTEGER,
target_language INTEGER,
translation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# Insert translations into database
for original, translated in zip(original_texts, translations):
cursor.execute(
"INSERT INTO translations (original_text, translated_text, source_language, target_language) VALUES (?, ?, ?, ?)",
(original, translated, 1, 2) # Replace with your actual language codes
)
# Commit the changes
conn.commit()
conn.close()
```
## Next Steps
Once you've retrieved your translations, you can:
1. **Display them** to your users
2. **Store them** for future reference
3. **Process them further** with additional NLP tools
4. **Use them in your application logic** to enable multilingual functionality
The simplicity of the response format makes it easy to integrate translations wherever they're needed in your workflow, whether you're building a multilingual website, an educational app, or an international communication tool.
By understanding how to effectively use this endpoint, you can create smoothly functioning multilingual applications that deliver high-quality translations to your users at exactly the right moment in their journey.
# Get Text-to-Speech Task Status
Source: https://docs.camb.ai/api-reference/endpoint/get-tts-result
get /tts/{task_id}
Retrieves the current status of a Text-to-Speech task using the specified `task_id`.
This route is the legacy status check that pairs with deprecated `POST /tts`. For greenfield work, prefer streaming: call `POST /tts-stream` and let audio flow continuously instead of polling here.
This endpoint allows you to check on the progress of your Text-to-Speech tasks. When you submit a text-to-speech request, our system begins processing your audio in the background. This endpoint lets you monitor that process from start to finish, keeping you informed about when your audio will be ready.
## How to Use This Endpoint
To check the status of your Text-to-Speech task, simply send a `GET` request to this endpoint with the `task_id` you received when you submitted your original request. The system will respond with detailed information about where your task stands in the processing pipeline.
## Understanding the Response
When you call this endpoint, you'll receive a status response that includes several key pieces of information:
* **Status Code**: Indicates whether the task is still processing, has completed successfully, or encountered an error.
* **Result Information**: For completed tasks, includes the `run_id` needed to download your finished audio file.
### Status Types Explained
Your text-to-speech task will pass through different states as our system processes it. Understanding these status codes will help you properly handle each situation in your application:
| Status | Description | Next Step |
| :----------------- | :----------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- |
| `SUCCESS` | Your audio generation has completed successfully | Use the `run_id` to download your finished audio |
| `PENDING` | Your task is currently being processed by our system. | Continue polling until completion. |
| `TIMEOUT` | The processing time exceeded the allowed limit. | Consider breaking text into smaller segments. |
| `ERROR` | Something went wrong during processing. | Check error details and try submitting again. |
| `PAYMENT_REQUIRED` | Your account requires additional credits for this operation. | Add credits to your account or upgrade your plan by heading to the [billing page](https://studio.camb.ai/billing) and retry the request. |
## Example Code
```python [expandable] theme={null}
import requests
import time
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
}
# The task_id you received when submitting your TTS request
task_id = "your_task_id" # Replace with your actual task ID
# Function to check status and wait for completion
def check_tts_status(task_id):
print("Checking task status...")
# Set up polling interval (in seconds)
polling_interval = 5
while True:
# Make the status request
response = requests.get(
f"https://client.camb.ai/apis/tts/{task_id}",
headers=headers
)
# Check if the request was successful
response.raise_for_status()
# Parse the response
status_data = response.json()
print(f"Current status: {status_data['status']}")
# Use match-case statement to handle different status types
match status_data['status']:
case 'SUCCESS':
print("Task complete!")
run_id = status_data['run_id']
print(f"Your audio is ready for download using run_id: {run_id}")
return run_id
case 'PENDING':
print("Task still processing...")
# Continue to next iteration of while loop
case 'TIMEOUT':
print("Task timed out. Consider using shorter text segments.")
return None
case 'ERROR':
print(f"Task failed with error: {status_data.get('error', 'Unknown error')}")
return None
case 'PAYMENT_REQUIRED':
print("Additional credits required to process this request.")
return None
case _: # Default case for any unexpected status values
print(f"Unexpected status: {status_data['status']}")
return None
# If still pending, wait and check again
if status_data['status'] == 'PENDING':
print(f"Task still in progress. Checking again in {polling_interval} seconds...")
time.sleep(polling_interval)
else:
# Exit the loop for non-pending statuses after handling them above
break
# Call the function to monitor your task
run_id = check_tts_status(task_id)
# If task completed successfully, download the audio
if run_id:
print("Proceed to download the audio file using the run_id!")
```
This polling mechanism gives you flexibility to build applications that can provide real-time feedback to users about their text-to-speech conversions. You can adjust the polling interval based on your specific needs, checking more frequently for time-sensitive applications or less frequently for background tasks.
## Next Steps
Once your task shows a status of `SUCCESS`, you'll receive a `run_id` in the response. This `run_id` is your key to accessing the generated audio. Take this identifier and use it with the [`/tts-result/{run_id}`](get-tts-run-info) endpoint to download your finished audio file and put it to work in your application.
# Get Text-to-Speech Result
Source: https://docs.camb.ai/api-reference/endpoint/get-tts-run-info
get /tts-result/{run_id}
Retrieves the result of a specific Text-to-Speech run using the provided `run_id`.
You’d reach this step after the old async `POST /tts` job completes. That whole pattern is deprecated—new builds should stream speech with `POST /tts-stream` rather than waiting on a finished run and fetching bytes afterward.
This endpoint is the final step in your text-to-speech journey, where you retrieve your completed audio file. Once your task has reached a `SUCCESS` status and you've received a `run_id`, you can use this endpoint to access your generated audio and incorporate it into your application.
## How to Use this Endpoint
Retrieving your generated audio is straightforward - simply make a `GET` request to this endpoint with the `run_id` you received when your task completed. The system will respond by providing your audio in your preferred format.
## Understanding Response Options
This endpoint offers flexibility in how you receive your audio content. You can specify your preference using the `output_type` parameter:
| Output Type | Description | Best For |
| :---------- | :-------------------------------------------------- | :-------------------------------------------- |
| `raw_bytes` | Direct streaming of audio data (default option) | Immediate playback or saving to local storage |
| `file_url` | JSON response with a URL to download the audio file | When you need to share or store the audio URL |
### Working with Raw Bytes
When using the default `raw_bytes` output type, the endpoint streams the audio data directly to your application. This approach is ideal when you want to:
1. Save the audio file to your local system
2. Process the audio data immediately in your application
3. Play the audio without storing it permanently
The streaming approach is particularly efficient for handling larger audio files as it processes the data in manageable chunks rather than loading everything into memory at once.
### Working with File URLs
If you prefer to receive a URL pointing to your audio file instead of the raw data, specify `output_type=file_url`. The response will be a JSON object containing a URL where the audio file can be accessed. This approach is beneficial when:
1. You need to share the audio file with others
2. Embed the audio in web content
3. Handle the download process separately from retrieval
Note that file URLs have an expiration time, so download or use them promptly rather than storing them long-term.
## Examples
### Saving Audio to a File
Here's how to retrieve and save your generated audio using Python:
```python [expandable] theme={null}
import requests
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
}
# The run_id you received when your task completed successfully
run_id = 12345 # Replace with your actual `run_id`
def download_audio_file(run_id, output_filename="generated_speech.flac"):
"""
Downloads the generated audio file and saves it to the specified location.
Args:
run_id: The unique identifier for the completed TTS task
output_filename: Where to save the audio file (defaults to 'generated_speech.flac')
Returns:
bool: True if successful, False otherwise
"""
print(f"Downloading audio for run_id: {run_id}")
try:
# Make the request with streaming enabled
# The 'stream=True' parameter is crucial for handling the audio data efficiently
response = requests.get(
f"https://client.camb.ai/apis/tts-result/{run_id}",
headers=headers,
stream=True # This enables processing the response in chunks
)
# Check if the request was successful
response.raise_for_status()
# Save the streaming audio to a file
with open(output_filename, "wb") as audio_file:
# Process the response in chunks to handle large audio files efficiently
# The chunk_size determines how much data to process at once
for chunk in response.iter_content(chunk_size=1024):
if chunk: # Filter out keep-alive chunks
audio_file.write(chunk)
print(f"Audio successfully saved to {output_filename}!")
return True
except requests.exceptions.RequestException as e:
print(f"Error downloading audio: {e}")
return False
# Call the function to download your audio
success = download_audio_file(run_id)
if success:
print("You can now use this audio file in your application!")
```
### Getting a File URL
If you prefer to receive a URL to the audio file instead:
```python [expandable] theme={null}
import requests
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
}
# The run_id you received when your task completed successfully
run_id = 12345 # Replace with your actual `run_id`
# Request a URL instead of raw bytes
params = {
"output_type": "file_url"
}
# Make the request
response = requests.get(
f"https://client.camb.ai/apis/tts-result/{run_id}",
headers=headers,
params=params
)
# Check if the request was successful
response.raise_for_status()
# Get the URL from the response
url_data = response.json()
audio_url = url_data.get("output_url")
print(f"Your audio is available at: {audio_url}")
print("You can now share this URL or use it to embed the audio in your application.")
```
## Next Steps
Now that you've successfully retrieved your generated audio, you can:
1. Incorporate it into your applications or websites.
2. Process it further with audio editing tools.
3. Combine multiple audio segments into a cohesive narrative.
4. Share it with your users through your platform.
With these capabilities, you have everything you need to build rich, accessible voice experiences into your applications.
# List Dictionaries
Source: https://docs.camb.ai/api-reference/endpoint/list-dictionaries
get /dictionaries
Retrieve all dictionaries available in the workspace associated with your API key.
Dictionaries can be created and managed either through the [CAMB.AI Studio](https://studio.camb.ai) interface or programmatically via the CAMB.AI APIs.
## Understanding Terminology Management in Localization
Dictionaries are centralized repositories for terminology management across languages, essential for maintaining consistent terminology in specialized industries and branded materials. CAMB.AI's dictionary system ensures key terms, product names, and industry jargon remain consistent throughout localized content.
Each dictionary in your workspace contains curated terminology pairs defining how specific terms should be translated across target languages, addressing one of localization's key challenges: consistent and accurate specialized vocabulary.
## The Role of Dictionaries in Your Localization Pipeline
Dictionaries enhance your translation workflows by:
1. **Ensuring Terminology Consistency** across all translations regardless of context
2. **Preserving Domain Expertise** by encoding specialized knowledge
3. **Protecting Brand Language** across multiple languages
4. **Streamlining Quality Control** by establishing pre-approved translations
Within CAMB.AI, dictionaries integrate seamlessly with translation workflows, automatically applying terminology rules during content processing.
## Using This Endpoint
To retrieve all dictionaries in your workspace:
```
GET /dictionaries
```
No parameters required. Authentication occurs via your API key.
## Dictionary Management Workflow
Dictionaries can be created, updated, and deleted through either the CAMB.AI Studio interface or directly via REST API calls. Below is an overview of both approaches:
### 1. Via CAMB.AI Studio
1. **Create dictionaries** via Studio, organized by domain or project or by uploading a file that contains your terms and their translations. Refer to this [page](create-dictionary-from-file) for more details.
2. **Add terminology entries** with source terms and approved translations
3. **Retrieve dictionary information** via API or Studio to identify available dictionaries
4. **Apply dictionaries to translations** by referencing their IDs in requests
### 2. Programmatically via API
The CAMB.AI API now exposes endpoints to fully manage dictionaries and their entries. Use these endpoints to build CI/CD pipelines, integrate with custom tools, or automate bulk imports/exports.
## Integrating Dictionaries into Translation Workflows
Apply dictionaries in two primary ways:
### 1. Direct Application in Translation Requests
Specify dictionary IDs when making translation requests:
```json [expandable] theme={null}
{
"source_language": "en-us", // Locale tag. Numeric IDs (e.g. "1") still work but are deprecated.
"target_language": "es-es",
"text": "The patient's vital signs remained stable throughout the procedure.",
"dictionaries": [42, 63] // Apply Medical and Legal dictionaries
}
```
### 2. Dictionary Selection Based on Content Type
Select dictionaries programmatically based on content analysis:
```python [expandable] theme={null}
# Pseudo-code example
def translate_with_appropriate_dictionaries(text, source_lang, target_lang):
# Get available dictionaries
dictionaries = requests.get(
"https://client.camb.ai/apis/dictionaries",
headers={"x-api-key": API_KEY}
).json()['dictionaries']
# Select dictionaries based on content
selected_dictionary_ids = []
if contains_medical_terms(text):
medical_dict = next((d for d in dictionaries if d['name'] == 'Medical Terminology'), None)
if medical_dict:
selected_dictionary_ids.append(medical_dict['id'])
# Translate with selected dictionaries
return requests.post(
"https://client.camb.ai/apis/translate",
json={
"source_language": source_lang,
"target_language": target_lang,
"text": text,
"dictionaries": selected_dictionary_ids
},
headers={"x-api-key": API_KEY}
).json()
```
## Best Practices for Dictionary Management
For effective dictionary implementation:
1. **Maintain Regularly**: Establish review cycles and track updates using the `updated_at` timestamp
2. **Apply Strategically**: Use complementary dictionaries and consider application order when terminologies overlap
3. **Govern Collaboratively**: Establish clear ownership and documentation standards for dictionaries
## Related Endpoints
The `/dictionaries` endpoint works in conjunction with several other endpoints in the CAMB.AI API ecosystem:
Apply dictionaries during translation to ensure consistent terminology across languages. Custom dictionaries help maintain brand voice and technical accuracy.
Use dictionaries when generating dubbed content to ensure specialized terminology is properly voiced in the target language with appropriate pronunciation.
Incorporate dictionaries when creating localized stories to maintain consistent terminology and branding elements across narratives in different languages.
Apply dictionaries during the text-to-speech process after translation to ensure specialized terms are properly pronounced in the generated audio output.
This interconnected system provides comprehensive support for terminology management throughout your localization workflow.
# List Folders
Source: https://docs.camb.ai/api-reference/endpoint/list-folders
get /folders
The List Folders endpoint provides comprehensive access to your organizational structure within the CAMB.AI workspace, allowing you to retrieve and explore the folders that serve as containers for your audio processing projects. This endpoint becomes increasingly valuable as your workspace grows, offering powerful filtering capabilities to help you navigate complex project hierarchies efficiently.
## Overview
Understanding how folders work in your CAMB.AI workspace is essential for effective project management. Think of folders as digital filing cabinets that organize related tasks, transcriptions, audio files, and other assets. What makes these folders particularly powerful is their universal nature across the entire CAMB.AI platform - every task you create through any API endpoint, whether it's audio separation, transcription, translation, voice synthesis, or any other processing service, can be organized within these same folder structures.
## When to Use This Endpoint
This endpoint serves multiple strategic purposes in your workflow management. During initial application setup, you might retrieve all folders to populate navigation menus or project selection interfaces. As your workspace evolves, you'll frequently use the search functionality to quickly locate specific project containers without manual browsing through extensive folder collections.
The filtering capabilities make this endpoint particularly powerful for building responsive user interfaces. Rather than overwhelming users with hundreds of folders, you can implement progressive loading strategies using the limit parameter, or provide real-time search functionality that helps users find exactly what they're looking for as they type.
## Key Parameters and Their Strategic Applications
### Limit Parameter: Balancing Performance and Completeness
The limit parameter operates as your primary tool for controlling response size and optimizing application performance. When you specify a limit between 1 and 100, you're making a strategic decision about how much data to retrieve in a single request.
### Search Query: Intelligent Folder Discovery
The search functionality transforms how users interact with large folder collections by implementing intelligent partial matching against folder names. This case-insensitive search mechanism understands that users rarely remember exact folder names, instead supporting natural search patterns that match how people actually think about their projects.
## Integration with Broader Workspace Management
The List Folders endpoint works most effectively when integrated with other workspace management features. Folder information often serves as the foundation for task creation workflows across every API endpoint in the CAMB.AI platform, where users select organizational containers before initiating any type of processing operation, whether that's audio separation, transcription, translation, voice synthesis, or other specialized services.
This cross-service integration creates powerful organizational possibilities. Consider a multimedia localization project where you might use audio separation to isolate speaker tracks, transcription services to generate text, translation APIs to convert content into multiple languages, and voice synthesis to create dubbed audio. All of these interconnected tasks can be organized within a single project folder, creating a comprehensive workspace that tells the complete story of your content transformation journey.
# List all Voices
Source: https://docs.camb.ai/api-reference/endpoint/list-voices
get /list-voices
Retrieves a comprehensive list of all available voices, including public voices, shared voices, and custom-created voices. Each voice entry provides detailed attributes such as a unique identifier, voice name, gender, and age, ensuring precise selection and usability.
## Understanding the Voice Ecosystem
This endpoint serves as your gateway to our platform's complete voice library, providing a unified view of all voices available to your account. The returned collection includes three distinct categories of voices:
1. **Public Voices**: These are system-provided voices available to all users. They offer professional-quality speech synthesis across multiple languages, accents, and demographic characteristics.
2. **Custom Voices**: These are unique voices you've created using our voice cloning technology. Custom voices allow you to maintain brand consistency or create specific character voices for your applications.
3. **Shared Voices**: These are voices created by other users who have chosen to make them available on the marketplace. Shared voices expand your options without requiring you to create custom voices from scratch.
By accessing this comprehensive catalog, you can explore the full range of vocal options before deciding which voice best suits your specific use case.
## Using the Endpoint
To retrieve the list of all available voices, simply send a GET request to this endpoint:
```
GET /list-voices
```
No parameters are required for this request. The system will return an array containing detailed information about each available voice.
### Example Response
```json [expandable] theme={null}
{
"voices": [
{
"id": 20305,
"voice_name": "Alice",
"gender": 2,
"age": 65,
"language": "en-us",
"transcript": null,
"description": "A warm, steady voice with a calm tone and a touch of enthusiastic energy, perfect for engaging narration.",
"is_published": false
},
{
"id": 147320,
"voice_name": "Gary",
"gender": 1,
"age": 35,
"language": "en-us",
"transcript": null,
"description": "A rich, warm voice brimming with emotion and dynamic expression, perfect for dramatic readings that captivate the listener.",
"is_published": false
}
// Additional voice entries...
]
}
```
## Voice Selection Best Practices
When working with the voice catalog, consider these approaches to ensure optimal results:
### 1. Filter Locally for Specific Requirements
Since the endpoint returns all available voices, implement client-side filtering to narrow down options based on your specific requirements. Common filtering criteria include:
* **Gender**: Filter based on whether you need male, female, or gender-neutral voices
* **Age range**: Select voices within specific age brackets to match your target audience
* **Language**: Filter for voices that support the languages your content requires
* **Publication status**: Distinguish between private and publicly shared voices
### 2. Implement Voice Previews
Before committing to a specific voice for your project, provide users with the ability to preview different voices using small audio samples. This can be accomplished by:
1. Selecting a subset of voices from the catalog that match your initial criteria
2. Using the text-to-speech endpoint with a short, consistent text sample for each voice
3. Presenting these samples to users or stakeholders to gather feedback
### 3. Consider Voice Consistency
When building applications with extensive voice interaction:
* Maintain consistency by using the same voice throughout a user journey
* Document your selected voice IDs in your application configuration
* Consider creating backup voice selections in case primary choices become unavailable
### 4. Optimize for Different Content Types
Different voice characteristics work better for different types of content:
* **Informational content**: Clear, measured voices with neutral emotional tones
* **Narrative content**: Expressive voices with good dynamic range
* **Instructional content**: Patient, articulate voices with excellent clarity
* **Conversational interfaces**: Natural, friendly voices with appropriate pacing
## Relationship with Other Endpoints
The `/list-voices` endpoint works in conjunction with several other endpoints in the API:
* Use this endpoint to discover available voices
* Use the [`/tts`](create-tts) endpoint to generate speech with your selected voice
* Use the [`/voices/create-custom-voice`](create-custom-voice) endpoint to add new voices to this list
* Use the [`/text-to-voice`](create-text-to-voice) endpoint to generate voices from text descriptions
This interconnected system of endpoints gives you complete control over voice discovery, creation, and utilization across your applications.
# Get Subtitle Task Status
Source: https://docs.camb.ai/api-reference/endpoint/poll-subtitle-result
get /sub/{task_id}
Retrieves the current status of a subtitle task using the specified `task_id`.
Monitor the progress of your subtitle generation in real-time with our status tracking endpoint. This essential companion to our subtitle service lets you check the current state of your media processing job across every requested language. By polling this endpoint, you can track your subtitle task's lifecycle and handle potential processing issues proactively.
This endpoint works in conjunction with the main `/sub` endpoint, which initiates the subtitle process and provides the `task_id` required for status checks.
## Implementing Status Checking
Here's how to implement subtitle status monitoring in your application using Python:
```python [expandable] theme={null}
import requests
import time
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def check_subtitle_status(task_id):
"""
Polls the status endpoint to track a subtitle task's progress.
Continues checking until the task reaches a terminal state.
"""
if not task_id:
print("Error: No task ID provided")
return None
terminal_states = ["SUCCESS", "ERROR"]
current_status = None
while current_status not in terminal_states:
try:
# Make the status request
response = requests.get(
f"https://client.camb.ai/apis/sub/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Extract the status information
status_data = response.json()
current_status = status_data.get("status")
# Display current progress information
print(f"Status: {current_status}")
if current_status == "PENDING":
time.sleep(15)
continue
# Handle completed state
if current_status == "SUCCESS":
print("Subtitle generation completed successfully!")
return status_data
# Handle failed state
if current_status == "ERROR":
print(f"Subtitle generation failed: {status_data.get('message')}")
return status_data
# Wait before next check to avoid excessive requests
time.sleep(15) # Poll every 15 seconds
except requests.exceptions.RequestException as e:
print(f"Error checking subtitle status: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
return None
# Example usage with a task_id from a subtitle request
task_id = "your_task_id" # Replace with your actual task ID
final_status = check_subtitle_status(task_id)
```
## Best Practices for Status Monitoring
Ensure efficient tracking of your subtitle tasks with these professional recommendations:
1. **Optimized Polling Intervals**: Start with 15-second intervals and gradually increase to 60 seconds for long media files
2. **Terminal State Handling**: Implement robust error handling for both success and failure scenarios
# Get Transcription Task Status
Source: https://docs.camb.ai/api-reference/endpoint/poll-transcription-result
get /transcribe/{task_id}
Retrieves the current status of a transcription task using the specified `task_id`.
Monitor the progress of your speech-to-text conversion in real-time with our status tracking endpoint. This essential companion to our transcription service lets you check the current state of your audio processing job and retrieve completed transcripts. By polling this endpoint, you can track your transcription task's lifecycle and handle potential processing issues proactively.
This endpoint works in conjunction with the main `/transcribe` endpoint, which initiates the transcription process and provides the `task_id` required for status checks.
## Implementing Status Checking
Here's how to implement transcription status monitoring in your application using Python:
```python [expandable] theme={null}
import requests
import time
# Your API authentication
headers = {
"x-api-key": "your-api-key", # Replace with your actual API key
"Content-Type": "application/json"
}
def check_transcription_status(task_id):
"""
Polls the status endpoint to track a transcription task's progress.
Continues checking until the task reaches a terminal state.
"""
if not task_id:
print("Error: No task ID provided")
return None
terminal_states = ["SUCCESS", "ERROR"]
current_status = None
while current_status not in terminal_states:
try:
# Make the status request
response = requests.get(
f"https://client.camb.ai/apis/transcribe/{task_id}",
headers=headers
)
# Verify the request was successful
response.raise_for_status()
# Extract the status information
status_data = response.json()
current_status = status_data.get("status")
# Display current progress information
print(f"Status: {current_status}")
if current_status == "PENDING":
time.sleep(15)
continue
# Handle completed state
if current_status == "SUCCESS":
print("Transcription completed successfully!")
return status_data
# Handle failed state
if current_status == "ERROR":
print(f"Transcription failed: {status_data.get('message')}")
return status_data
# Wait before next check to avoid excessive requests
time.sleep(15) # Poll every 15 seconds
except requests.exceptions.RequestException as e:
print(f"Error checking transcription status: {e}")
if hasattr(e, 'response') and e.response is not None:
print(f"Response content: {e.response.text}")
return None
return None
# Example usage with a task_id from transcription request
task_id = "your_task_id" # Replace with your actual task ID
final_status = check_transcription_status(task_id)
```
## Best Practices for Status Monitoring
Ensure efficient tracking of your transcription tasks with these professional recommendations:
1. **Optimized Polling Intervals**: Start with 15-second intervals and gradually increase to 60 seconds for long audio files
2. **Terminal State Handling**: Implement robust error handling for both success and failure scenarios
# Get Translated Text-to-Speech Status
Source: https://docs.camb.ai/api-reference/endpoint/poll-translated-tts-result
get /translated-tts/{task_id}
Monitors the progress of a Translated Text-to-Speech task using the provided `task_id`.
This endpoint enables you to track the status of your Translated Text-to-Speech requests. When you submit content for translation and audio generation, our system processes both operations as a unified background task. This endpoint provides detailed visibility into this combined process, allowing you to determine when your translated audio will be ready for use.
## Understanding This Endpoint
To monitor your Translated Text-to-Speech task progression, send a `GET` request to this endpoint with the `task_id` you received during your initial submission. The system will return comprehensive information about the current stage of processing for both the translation and audio generation components.
## Response Structure
When querying this endpoint, you'll receive a detailed status response containing several vital pieces of information:
* **Current Status**: Indicates the overall state of your combined translation and audio generation task.
* **Completion Details**: For successfully completed tasks, includes `run_id` necessary to access your translated text and generated audio file.
### Understanding Status Codes
Your translated text-to-speech request will move through various states during processing. Each status code represents a distinct situation that your application should be prepared to handle:
| Status | Meaning | Recommended Action |
| :----------------- | :---------------------------------------------------------------- | :-------------------------------------------------------------------------------------- |
| `SUCCESS` | Both translation and audio generation have completed successfully | Retrieve your translated text and audio using the provided IDs |
| `PENDING` | Your request is actively being processed | Continue monitoring at reasonable intervals |
| `TIMEOUT` | Processing exceeded the maximum allowed duration | Consider breaking your content into smaller segments |
| `ERROR` | A system-level issue occurred during processing | Check error details for specific information about what went wrong |
| `PAYMENT_REQUIRED` | Your account has insufficient credits for this operation | Visit your account's [billing page](https://studio.camb.ai/billing) to add more credits |
## Implementation Guidelines
For optimal integration of this endpoint into your applications, consider the following practices:
1. **Implement Progressive Polling**: Start with longer intervals between status checks, then decrease the interval as the task progresses through different states.
2. **Set Reasonable Timeouts**: Most translation and synthesis tasks complete within 2-5 minutes, depending on content length and complexity.
## Example Implementation in JavaScript
```javascript [expandable] theme={null}
// Monitoring a Translated Text-to-Speech task with progressive polling
async function monitorTranslatedTTSTask(taskId, apiKey) {
console.log("Beginning task monitoring...");
// Initial configuration
let pollInterval = 10000; // Start with 10-second intervals
let attempts = 0;
const maxAttempts = 30;
while (attempts < maxAttempts) {
attempts++;
try {
// Request current task status
const response = await fetch(`https://client.camb.ai/apis/translated-tts/${taskId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey
}
});
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
const statusData = await response.json();
console.log(`Status check #${attempts}: ${statusData.status}`);
// Adjust polling interval based on current stage
if (statusData.status === 'PENDING') {
console.log("Task is in progress...");
// Handle different status types
switch (statusData.status) {
case 'SUCCESS':
console.log("Task completed successfully!");
console.log(`Run ID: ${statusData.run_id}`);
return statusData; // Return the complete status object
case 'PENDING':
// Still processing, continue to next poll iteration
break;
case 'TIMEOUT':
console.error("Processing time exceeded. Consider shorter content segments.");
return null;
case 'ERROR':
console.error(`Processing error: ${statusData.error_message}`);
return null;
case 'PAYMENT_REQUIRED':
console.error("Insufficient credits. Please add more credits to your account.");
return null;
default:
console.error(`Unexpected status: ${statusData.status}`);
return null;
}
// Wait before next check
console.log(`Checking again in ${pollInterval/1000} seconds...`);
await new Promise(resolve => setTimeout(resolve, pollInterval));
} catch (error) {
console.error(`Error checking status: ${error.message}`);
return null;
}
}
console.error("Maximum monitoring attempts reached. Task may still be processing.");
return null;
}
```
## Performance Considerations
When integrating this status-monitoring endpoint into your applications, keep these performance factors in mind:
* **Request Frequency**: Avoid polling more frequently than every 3-5 seconds to prevent unnecessary load on both client and server.
* **Timeout Handling**: For longer texts, processing may take several minutes. Set appropriate client-side timeout expectations.
* **Error Resilience**: Network interruptions shouldn't affect your task processing; the task continues running server-side regardless of status checks.
## Next Steps
Once your task reaches the `SUCCESS` status, you'll receive a `run_id` for accessing both:
1. The generated audio file through the [`/tts-result/{run_id}`](get-tts-run-info) endpoint.
2. The translated text via the [`/translation-result/{run_id}`](get-translation-run-result) endpoint.
Armed with this identifier, you can integrate both the translation and audio components into your application's workflow, creating a seamless multilingual audio experience for your users.
# Get Translation Task Status
Source: https://docs.camb.ai/api-reference/endpoint/poll-translation-result
get /translate/{task_id}
Monitor the progress of your translation tasks with real-time status updates, enabling you to track completion and retrieve translated content when ready.
This endpoint serves as your window into the translation process, allowing you to monitor the status of tasks you've submitted through the `/translate` endpoint. By providing the unique `task_id` you received when initiating a translation, you can check whether your translation is still being processed, has completed successfully, or encountered an issue. When translation is complete, this endpoint also delivers your translated text.
## Understanding the Translation Lifecycle
When you submit a translation request, it goes through several stages before completion. This endpoint keeps you informed about which stage your task has reached:
### Status Types
The `status` field in the response will contain one of these values:
* **`PENDING`**: Your translation is currently in the processing queue or actively being translated. This indicates that everything is working as expected, but the translation is not yet complete. Continue polling at reasonable intervals.
* **`SUCCESS`**: The translation process has completed successfully. When you receive this status, your `run_id` is returned which the identifier that you would use to fetch your translations by using the [`/translation-result/{run_id}`](get-translation-run-result)
* **`ERROR`**: Something went wrong during the translation process. This could be due to invalid input parameters, server issues, or problems with the translation engine. The response may include additional details about the nature of the error.
* **`TIMEOUT`**: The translation task exceeded the maximum allowed processing time. This typically happens with extremely large translation requests or during periods of high system load. Consider breaking your request into smaller batches.
* **`PAYMENT_REQUIRED`**: Your account does not have sufficient credits or permissions to complete this translation. Please check your subscription status or contact support for assistance.
## Recommended Polling Strategy
Asynchronous operations like translation require a thoughtful approach to status checking:
1. **Start with short intervals**: Initially check every 1-2 seconds for very short translations
2. **Use exponential backoff**: Gradually increase the time between checks (e.g., doubling the wait time after each check)
3. **Set a maximum interval**: Don't let the wait time grow beyond 10-15 seconds
4. **Implement a timeout**: Establish a maximum total wait time for your application
This approach balances responsiveness with server efficiency, ensuring you get your translations promptly without overloading the system with unnecessary requests.
## Example: Monitoring Translation Progress
Here's how you might implement status checking for a translation task:
```python [expandable] theme={null}
import requests
import time
def check_translation_status(task_id, api_key, base_url="https://client.camb.ai/apis"):
"""
Check the status of a translation task with exponential backoff.
Parameters:
-----------
task_id : str
The unique identifier for the translation task
api_key : str
Your API authentication key
base_url : str
The base URL for the API endpoints
Returns:
--------
dict
The final response containing translations if successful
"""
headers = {
"x-api-key": api_key,
"Content-Type": "application/json"
}
# Initial polling parameters
wait_time = 1 # Start with 1 second
max_wait_time = 10 # Maximum seconds between polls
max_total_wait = 300 # Maximum total seconds to wait (5 minutes)
start_time = time.time()
while (time.time() - start_time) < max_total_wait:
# Get current status
response = requests.get(
f"{base_url}/translate/{task_id}",
headers=headers
)
# Check for API errors
if response.status_code != 200:
print(f"Error checking status: HTTP {response.status_code}")
return None
status_data = response.json()
current_status = status_data.get("status")
# Handle each possible status
if current_status == "SUCCESS":
print("✅ Translation completed successfully!")
return status_data # Contains translations
elif current_status == "PENDING":
elapsed = round(time.time() - start_time)
print(f"⏳ Translation in progress... ({elapsed}s elapsed)")
elif current_status == "ERROR":
print("❌ Translation failed with an error.")
return status_data # May contain error details
elif current_status == "TIMEOUT":
print("⏰ Translation timed out on the server.")
return status_data
elif current_status == "PAYMENT_REQUIRED":
print("💰 Additional payment or credits required.")
return status_data
# Wait before checking again, with exponential backoff
time.sleep(wait_time)
wait_time = min(wait_time * 2, max_wait_time) # Double wait time but cap it
# If we've reached here, we've exceeded our maximum wait time
print("🛑 Client-side timeout: Maximum wait time exceeded")
return None
# Example usage:
api_key = "your-api-key" # Replace with your actual API key
task_id = "your_task_id" # Replace with your actual task ID
result = check_translation_status(task_id, api_key)
if result and result.get("status") == "SUCCESS":
print(f"Use the Run ID: {result.get('run_id')} to fetch your translated result.")
```
This function demonstrates a robust implementation of status polling with several key features:
1. **Exponential backoff**: The wait time between requests starts small and gradually increases, which is efficient for both short and long-running tasks
2. **Multiple status handling**: Each possible status value is handled appropriately
3. **Error reporting**: Meaningful error messages help diagnose issues
4. **Progress tracking**: The elapsed time is displayed to keep users informed
5. **Timeout protection**: Both client-side and server-side timeouts are accounted for
By implementing a similar approach in your application, you can create a responsive user experience that keeps users informed about translation progress while efficiently managing system resources.
## When to Stop Polling
You should stop polling when you receive one of these definitive statuses:
* **`SUCCESS`**: You've received your translations
* **`ERROR`**: The task failed and won't recover
* **`TIMEOUT`**: The server timed out the request
* **`PAYMENT_REQUIRED`**: Payment issues need to be resolved
Only the **`PENDING`** status indicates that you should continue polling.
With this endpoint, you gain visibility into the translation process, allowing your application to respond appropriately based on real-time status information and retrieve completed translations as soon as they're available.
# Create an SRT Flow
Source: https://docs.camb.ai/api-reference/endpoint/streaming/create-flow
post /flows
Create a stream flow: a standing SRT endpoint you can use as the source or a target of your streams.
## Overview
A **flow** is a standing SRT endpoint hosted by Camb.ai, independent of any
stream. Create one once, and use its URLs as the source or a target of any
number of streams, with no need to expose your own SRT infrastructure.
Flows come in two modes:
Camb.ai hosts an SRT endpoint your encoder **pushes to**. You get one or
two `push_urls` (primary/backup) and a `play_url` anyone with the key can
pull from.
Camb.ai **pulls from your** SRT endpoint (`primary_url`) and re-serves it
on a stable `play_url`, with optional failover to a `backup_url`.
## Using a flow with streams
The returned `play_url` is a normal SRT URL:
* **As a stream source** - set it as `source_stream.url` when
[creating a stream](create-new-stream). Your encoder pushes to the flow's
`push_urls`; the stream ingests from the flow.
* **As a stream target** - set it as a `target_streams[].url` with
`"type": 1` to deliver your processed output to the flow, then distribute
the flow's `play_url` to viewers or downstream systems.
Set a `passphrase` (10–79 characters) to encrypt the flow's endpoint. It is
embedded in the returned URLs and required to connect. To pull from an
upstream that is itself encrypted (caller mode), append its passphrase to
`primary_url` as a query parameter: `srt://host:port?passphrase=...`.
## Example: listener flow for a stadium encoder
```bash cURL theme={null}
curl -X POST "https://client.camb.ai/apis/flows" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "stadium-encoder",
"mode": "listener",
"failover": true
}'
```
```python Python theme={null}
import requests
payload = {
"label": "stadium-encoder",
"mode": "listener",
"failover": True,
}
response = requests.post(
"https://client.camb.ai/apis/flows",
headers={"x-api-key": "YOUR_API_KEY"},
json=payload,
)
response.raise_for_status()
flow = response.json()
print(flow["push_urls"]) # give these to your encoder
print(flow["play_url"]) # use this as source_stream.url
```
The response contains everything needed to use the flow:
```json Response theme={null}
{
"id": 42,
"label": "stadium-encoder",
"mode": "listener",
"failover": true,
"active": true,
"team_id": 7,
"key": "k3yk3yk3yk3yk3yk3yk3yk3yk",
"play_url": "srt://live.camb.ai:20121?streamid=play/42/k3yk3yk3yk3yk3yk3yk3yk3yk",
"push_urls": [
{
"role": "primary",
"url": "srt://live.camb.ai:20121?streamid=publish/42-primary/k3yk3yk3yk3yk3yk3yk3yk3yk"
},
{
"role": "backup",
"url": "srt://live.camb.ai:20121?streamid=publish/42-backup/k3yk3yk3yk3yk3yk3yk3yk3yk"
}
],
"passphrase": null
}
```
## Validation rules
* `label` must be unique within your team.
* `caller` mode requires `primary_url`; `listener` mode must not set URLs.
* `backup_url` requires `failover: true` (and is required for caller flows
with failover).
## Errors
* `403` - Your subscription does not include streaming.
* `422` - Validation error (see the rules above).
## Related endpoints
* [List SRT Flows](list-flows)
* [Get an SRT Flow](get-flow)
* [Update an SRT Flow](update-flow)
* [Delete an SRT Flow](delete-flow)
# Create a Stream
Source: https://docs.camb.ai/api-reference/endpoint/streaming/create-new-stream
post /stream
Create a live stream that ingests a source feed, processes it with AI in real time, and publishes dubbed, translated, or transcribed outputs.
## Overview
This endpoint is the entry point of the streaming lifecycle. It takes a source
feed, one or more processing pipelines, and one or more output destinations,
and returns a `stream_id` you use for every other lifecycle operation.
**Supported source protocols:** SRT is supported today. RTMP and HLS ingest
are coming soon.
## How a stream fits together
The request body is built from four blocks that reference each other by `id`:
`source_stream` - the live feed to ingest, e.g. `srt://ingest.example.com:9000`.
You can also use the play URL of a [stream flow](create-flow) here.
`audio_selections` - name the audio track(s) of the source you want to
process and declare their spoken language. Use
[Probe a Source Stream](probe-stream) to discover tracks, or start with
`$first_audio`.
`processing_profiles` define *how* audio is processed (demixing,
transcription, translation, revoicing, each `none`, `best_model`, or
`fast_model`). `pipelines` connect an audio selection to a profile and
declare the output assets to produce, each with a language.
`target_streams` - where the processed output goes. At least one is
required. Push to your own endpoint (SRT/RTMP), or let Camb.ai host the
output for you (SRT listener or HLS recording).
## Before you start
Collect the IDs the payload references:
* **Language IDs** - [`GET /source-languages`](/api-reference/endpoint/get-source-languages) and
[`GET /target-languages`](/api-reference/endpoint/get-target-languages). Languages are numeric IDs;
for example `1` is English (US) and `54` is Spanish (Spain).
The system handles multilingual inputs. If the source audio mixes several
languages, set `source_language` to the main one spoken; the others are
handled automatically.
* **Voice IDs** (optional) - [`GET /list-voices`](/api-reference/endpoint/list-voices). If you pass
voice IDs, dubbed speech uses those fixed voices. If you leave them out,
voices are cloned from the speakers in the source audio.
* **Dictionary IDs** (optional) - [`GET /dictionaries`](/api-reference/endpoint/list-dictionaries) for
custom terminology, up to 5.
When passing fixed voice IDs, include voices of different genders and tones.
The system matches each speaker in the source audio to the most suitable
voice from your list, so a varied list produces better matches.
A pipeline that produces an `audio` output must also declare a `subtitle`
output in the same pipeline; the transcript drives the dubbing. You do not
have to route the subtitle asset to a target.
## Example: dub a football match into Spanish
The example ingests the SRT feed of a football match, dubs the English
commentary (`1`) into Spanish (`54`), and pushes the dubbed program (original
video plus Spanish commentary) to an SRT destination of your own.
Fastest way to test: copy this payload, adjust it to your setup, and paste
it into the **Try it** body - the form fields fill in automatically from the
pasted JSON. Then press Send.
```bash cURL theme={null}
curl -X POST "https://client.camb.ai/apis/stream" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Saturday Match Live Dub",
"description": "Football match commentary dubbed from English into Spanish",
"end_time": "2026-08-01T21:45:00Z",
"timezone": "UTC",
"voices": [12345],
"source_stream": {
"id": "match-feed",
"url": "srt://ingest.example.com:9000",
"latency": 2000,
"category": 2
},
"audio_selections": [
{
"id": "commentary",
"source": "$first_audio",
"source_language": 1
}
],
"processing_profiles": [
{
"id": "dubbing",
"demixing": "best_model",
"transcribing": "best_model",
"translating": "best_model",
"revoicing": "best_model"
}
],
"pipelines": [
{
"id": "spanish",
"profile": "dubbing",
"audio_selection": "commentary",
"outputs": [
{ "id": "es-audio", "kind": "audio", "language": 54 },
{ "id": "es-subtitle", "kind": "subtitle", "language": 54 }
]
}
],
"target_streams": [
{
"id": "spanish-out",
"url": "srt://delivery.example.com:9100",
"type": 1,
"inputs": [
{ "asset_id": "es-audio" },
{ "passthrough_selector": "v:0" }
]
}
]
}'
```
```python Python theme={null}
import requests
payload = {
"name": "Saturday Match Live Dub",
"description": "Football match commentary dubbed from English into Spanish",
"end_time": "2026-08-01T21:45:00Z", # streams always need an end time
"timezone": "UTC",
"voices": [12345], # from GET /list-voices
"source_stream": {
"id": "match-feed",
"url": "srt://ingest.example.com:9000",
"latency": 2000, # recommended SRT latency (ms)
"category": 2, # sports and entertainment
},
"audio_selections": [
{
"id": "commentary",
"source": "$first_audio",
"source_language": 1, # English (US)
}
],
"processing_profiles": [
{
"id": "dubbing",
"demixing": "best_model",
"transcribing": "best_model",
"translating": "best_model",
"revoicing": "best_model",
}
],
"pipelines": [
{
"id": "spanish",
"profile": "dubbing",
"audio_selection": "commentary",
"outputs": [
{"id": "es-audio", "kind": "audio", "language": 54}, # Spanish (Spain)
{"id": "es-subtitle", "kind": "subtitle", "language": 54},
],
}
],
"target_streams": [
{
"id": "spanish-out",
"url": "srt://delivery.example.com:9100",
"type": 1, # SRT caller: Camb.ai pushes to your endpoint
"inputs": [
{"asset_id": "es-audio"},
{"passthrough_selector": "v:0"}, # forward the original video
],
}
],
}
response = requests.post(
"https://client.camb.ai/apis/stream",
headers={"x-api-key": "YOUR_API_KEY"},
json=payload,
)
response.raise_for_status()
print(response.json())
```
A successful request returns the stream ID and the output URLs:
```json Response theme={null}
{
"stream_id": 1234,
"task_id": "b8f2f1f0-3c6a-4f5e-9b2a-1c2d3e4f5a6b",
"stream_url_for_languages": [
{
"languages": [54],
"url": "srt://delivery.example.com:9100"
}
]
}
```
## Scheduling
Every stream needs an `end_time` (with its `timezone`); the stream stops
automatically at that moment. `start_time` is optional: omit it to start
right away, or set it to schedule the stream for later.
```json theme={null}
{
"start_time": "2026-08-01T19:30:00Z",
"end_time": "2026-08-01T21:45:00Z",
"timezone": "UTC"
}
```
Scheduling rules:
* Times are ISO 8601 with a UTC offset, and the `timezone` (IANA name) must
match their offset.
* `start_time` cannot be in the past and at most 7 days in the future.
* `end_time` must be at least 15 minutes after the start.
To end a stream before its `end_time`, [delete it](delete-stream). To extend
or shorten a running stream, [update](update-stream) its `end_time`.
## Choosing targets
| You want to... | Use |
| -------------------------------------- | ------------------------------------------------------ |
| Push to your own SRT endpoint | `"type": 1` with your `url` |
| Push to an RTMP ingest (e.g. YouTube) | `"type": 2` (or `4` for YouTube) with the ingest `url` |
| Let viewers pull from Camb.ai over SRT | `"type": 6`, omit `url`; the play URL is returned |
| Get a Camb.ai-hosted HLS recording | `"type": 3`, omit `url`; the playback URL is returned |
Each target lists `inputs`: pipeline outputs by `asset_id`, and untouched
source tracks by `passthrough_selector` (e.g. `v:0` for the video). Source
tracks that are not replaced by a pipeline output are forwarded automatically
unless you set `passthrough_policy` to `none`.
## Errors
* `402` - Insufficient credits for the requested configuration.
* `422` - Validation error: missing required blocks, an `id` reference that
doesn't resolve (e.g. a pipeline referencing an unknown profile), invalid
language IDs, or malformed URLs.
## Related endpoints
* [Probe a Source Stream](probe-stream) - inspect the source before creating
* [Get Stream Status](get-stream-status) - monitor state and output URLs
* [Update a Stream](update-stream) - reschedule, reconfigure, or toggle dubbing live
* [Delete a Stream](delete-stream) - terminate a running or scheduled stream
* [Create an SRT Flow](create-flow) - standing SRT endpoints usable as source or target
# Create a Stream Template
Source: https://docs.camb.ai/api-reference/endpoint/streaming/create-template
post /stream/templates/
Save a created stream's configuration as a named template.
## Overview
Saves an existing stream's configuration under a name, so the same setup can
be recreated later without rebuilding the payload. The template stores no
configuration of its own: applying it with
[Use a Stream Template](use-template) replays the referenced stream's
original creation payload.
The `stream_id` must belong to a stream created in your workspace. Template
names are unique per workspace, and each workspace can hold at most 20
templates; a duplicate name or a full workspace returns `409`.
```bash cURL theme={null}
curl -X POST "https://client.camb.ai/apis/stream/templates/" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "matchday-dubbing", "stream_id": 4821}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://client.camb.ai/apis/stream/templates/",
headers={"x-api-key": "YOUR_API_KEY"},
json={"name": "matchday-dubbing", "stream_id": 4821},
)
response.raise_for_status()
print(response.json())
```
```json Response theme={null}
{
"id": 12,
"name": "matchday-dubbing",
"stream_id": 4821
}
```
## Related endpoints
* [List Stream Templates](list-templates)
* [Use a Stream Template](use-template)
* [Delete a Stream Template](delete-template)
# Delete an SRT Flow
Source: https://docs.camb.ai/api-reference/endpoint/streaming/delete-flow
delete /flows/{flow_id}
Delete a stream flow and shut down its SRT endpoint.
## Overview
Deletes a flow and shuts down its SRT endpoint. Its URLs stop working
immediately.
Deletion is permanent, and a new flow gets new URLs and a new key. Make sure
no encoders or streams are still using this flow before deleting it.
```bash cURL theme={null}
curl -X DELETE "https://client.camb.ai/apis/flows/42" \
-H "x-api-key: YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.delete(
"https://client.camb.ai/apis/flows/42",
headers={"x-api-key": "YOUR_API_KEY"},
)
response.raise_for_status()
print(response.json())
```
```json Response theme={null}
{ "status": "deleted", "id": 42 }
```
## Errors
* `404` - No flow with this ID belongs to your team.
## Related endpoints
* [Create an SRT Flow](create-flow)
* [List SRT Flows](list-flows)
# Delete a Stream
Source: https://docs.camb.ai/api-reference/endpoint/streaming/delete-stream
delete /stream/{stream_id}
Delete a stream, stopping it if it is live.
## Overview
Deletes a stream. If the stream is live, processing stops and outputs are
finalised; a scheduled stream is cancelled. The stream's status becomes `4`
(ended).
Deleting does not erase the stream's history: you can still call
[`GET /stream/{stream_id}`](get-stream-status) afterwards to read its final
state. Streams stop on their own at their `end_time`; use this endpoint to end
one earlier.
A deleted stream cannot be restarted. To run the same setup again, create a
new stream with the same payload, or use [flows](create-flow) as your
endpoints so encoders and viewers keep the same URLs across runs.
```bash cURL theme={null}
curl -X DELETE "https://client.camb.ai/apis/stream/1234" \
-H "x-api-key: YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.delete(
"https://client.camb.ai/apis/stream/1234",
headers={"x-api-key": "YOUR_API_KEY"},
)
response.raise_for_status()
print(response.json())
```
## Errors
* `404` - No stream with this ID belongs to your team.
* `422` - Invalid `stream_id`.
## Related endpoints
* [Create a Stream](create-new-stream)
* [Get Stream Status](get-stream-status)
* [Update a Stream](update-stream)
# Delete a Stream Template
Source: https://docs.camb.ai/api-reference/endpoint/streaming/delete-template
delete /stream/templates/{template_id}
Delete a stream template from your workspace.
## Overview
Removes a template from your workspace. Only the template entry is deleted:
the stream it was saved from, and any streams created from the template, are
unaffected.
Each workspace can hold at most 20 templates. Once the limit is reached,
saving a new template requires deleting one first.
Templates are scoped to your workspace: requesting a template that belongs to
another workspace returns `404`.
```bash cURL theme={null}
curl -X DELETE "https://client.camb.ai/apis/stream/templates/12" \
-H "x-api-key: YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.delete(
"https://client.camb.ai/apis/stream/templates/12",
headers={"x-api-key": "YOUR_API_KEY"},
)
response.raise_for_status()
print(response.json())
```
```json Response theme={null}
{
"id": 12
}
```
## Related endpoints
* [List Stream Templates](list-templates)
* [Use a Stream Template](use-template)
# Get an SRT Flow
Source: https://docs.camb.ai/api-reference/endpoint/streaming/get-flow
get /flows/{flow_id}
Retrieve a stream flow, including its play and push URLs.
## Overview
Returns the full details of one flow, including its `play_url`, `push_urls`,
and access `key`.
```bash cURL theme={null}
curl -X GET "https://client.camb.ai/apis/flows/42" \
-H "x-api-key: YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.get(
"https://client.camb.ai/apis/flows/42",
headers={"x-api-key": "YOUR_API_KEY"},
)
response.raise_for_status()
print(response.json())
```
## Errors
* `404` - No flow with this ID belongs to your team.
## Related endpoints
* [Create an SRT Flow](create-flow)
* [Update an SRT Flow](update-flow)
* [Delete an SRT Flow](delete-flow)
# Get Stream Status
Source: https://docs.camb.ai/api-reference/endpoint/streaming/get-stream-status
get /stream/{stream_id}
Retrieve the current status of a stream, including source details and the state and URLs of every output.
## Overview
Returns the current state of a stream. The response shape is the same whether
the stream is scheduled, live, or finished, which makes it suitable for
dashboards and polling loops.
Use it to:
* Track the stream through its lifecycle (`scheduled` → `setting up` →
`started` → `ended`).
* Read the playback URLs of Camb.ai-hosted outputs (SRT listener, HLS
recording).
* Check per-target delivery state and surface errors.
When polling, a cadence of 5–15 seconds is plenty. Back off once the stream
reaches a terminal status (`4`, `5`, or `6`).
```bash cURL theme={null}
curl -X GET "https://client.camb.ai/apis/stream/1234" \
-H "x-api-key: YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.get(
"https://client.camb.ai/apis/stream/1234",
headers={"x-api-key": "YOUR_API_KEY"},
)
response.raise_for_status()
print(response.json())
```
```json Response theme={null}
{
"stream_id": 1234,
"status": 3,
"source": {
"type": 1,
"playback_url": null
},
"targets": [
{
"id": "spanish-out",
"type": 1,
"state": "active",
"playback_url": null,
"destination_url": "srt://delivery.example.com:9100"
}
],
"scheduled_at": "2026-08-01T10:00:00Z",
"started_at": "2026-08-01T10:00:05Z",
"stopped_at": null,
"task_id": "b8f2f1f0-3c6a-4f5e-9b2a-1c2d3e4f5a6b",
"error": null
}
```
## Reading the response
* `status` - the stream lifecycle status: `1` scheduled, `2` setting up, `3`
started, `4` ended, `5` interrupted, `6` error.
* `targets[].state` - each output progresses `scheduled` → `active` →
`completed`, or `failed` on error.
* `targets[].playback_url` - set for Camb.ai-hosted outputs; this is where
you or your viewers connect.
* `targets[].destination_url` - set for push outputs; the endpoint Camb.ai is
delivering to.
* `error` - populated when `status` is `6`.
## Errors
* `404` - No stream with this ID belongs to your team.
* `422` - Invalid `stream_id`.
## Related endpoints
* [Create a Stream](create-new-stream)
* [Update a Stream](update-stream)
* [Delete a Stream](delete-stream)
# List SRT Flows
Source: https://docs.camb.ai/api-reference/endpoint/streaming/list-flows
get /flows
List all stream flows belonging to your team.
## Overview
Returns a summary of every flow owned by your team. Use
[Get an SRT Flow](get-flow) to retrieve a flow's URLs and key.
```bash cURL theme={null}
curl -X GET "https://client.camb.ai/apis/flows" \
-H "x-api-key: YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.get(
"https://client.camb.ai/apis/flows",
headers={"x-api-key": "YOUR_API_KEY"},
)
response.raise_for_status()
print(response.json())
```
```json Response theme={null}
[
{
"id": 42,
"label": "stadium-encoder",
"mode": "listener",
"failover": true,
"active": true,
"team_id": 7
}
]
```
## Related endpoints
* [Create an SRT Flow](create-flow)
* [Get an SRT Flow](get-flow)
# List Stream Templates
Source: https://docs.camb.ai/api-reference/endpoint/streaming/list-templates
get /stream/templates/
List the stream templates saved in your workspace.
## Overview
A stream template is a named snapshot of a previously created stream's
configuration, saved from the stream builder in the portal or with
[Create a Stream Template](create-template). Templates let you recreate a
proven setup, for example your matchday dubbing configuration, without
rebuilding the payload each time.
This endpoint returns every template saved in your workspace. Use
[Use a Stream Template](use-template) to retrieve a template's full payload.
Each workspace can hold at most 20 templates. When the limit is reached,
[delete a template](delete-template) before saving a new one.
```bash cURL theme={null}
curl -X GET "https://client.camb.ai/apis/stream/templates/" \
-H "x-api-key: YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.get(
"https://client.camb.ai/apis/stream/templates/",
headers={"x-api-key": "YOUR_API_KEY"},
)
response.raise_for_status()
print(response.json())
```
```json Response theme={null}
{
"templates": [
{
"id": 12,
"name": "matchday-dubbing",
"stream_id": 4821
},
{
"id": 15,
"name": "press-conference",
"stream_id": 5010
}
]
}
```
## Related endpoints
* [Create a Stream Template](create-template)
* [Use a Stream Template](use-template)
* [Create Stream](create-new-stream)
# Live Streaming Overview
Source: https://docs.camb.ai/api-reference/endpoint/streaming/overview
Dub, translate, and transcribe live streams in real time with the Camb.ai Streaming API.
The Streaming API takes a live feed, processes it with Camb.ai's AI pipeline
in real time, and publishes the results to the destinations you choose: dub a
football match's commentary into Spanish as it happens, push the dubbed feed
to YouTube, and
keep an HLS recording, all from one API call.
**Supported source protocols:** SRT is supported today. RTMP and HLS ingest
are coming soon.
## The streaming lifecycle
[`POST /stream/probe/`](probe-stream) - inspect the source and discover
its video, audio, and data tracks.
[`POST /stream`](create-new-stream) - configure source, pipelines, and
targets. You get back a `stream_id` and output URLs.
[`GET /stream/{stream_id}`](get-stream-status) - poll the stream status
and read the state and playback URLs of each output.
[`PATCH /stream/{stream_id}`](update-stream) - reschedule, reconfigure,
or apply live adjustments such as turning dubbing on and off.
[`DELETE /stream/{stream_id}`](delete-stream) - stop the stream, or let
it end automatically at its `end_time`.
## Core concepts
A stream's configuration is a small graph of blocks that reference each other
by `id`:
| Block | What it does |
| --------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `source_stream` | The live feed to ingest (an SRT URL, or a [flow](create-flow)'s play URL). |
| `audio_selections` | Names the source audio track(s) to process and their spoken language. |
| `processing_profiles` | How audio is processed: demixing, transcribing, translating, revoicing, each `none`, `best_model`, or `fast_model`. |
| `pipelines` | Connect one audio selection to one profile and declare output assets (dubbed audio, subtitles) per language. |
| `target_streams` | Where outputs go: your SRT/RTMP endpoints, YouTube, or Camb.ai-hosted SRT/HLS outputs. |
Language and voice choices are numeric IDs from the platform's catalog
endpoints: [`/source-languages`](/api-reference/endpoint/get-source-languages),
[`/target-languages`](/api-reference/endpoint/get-target-languages), and
[`/list-voices`](/api-reference/endpoint/list-voices).
## Stream flows
[Flows](create-flow) are standing SRT endpoints hosted by Camb.ai,
independent of any single stream. Use a flow when you want a stable ingest
point for your encoder (**listener** mode) or want Camb.ai to pull from your
infrastructure and re-serve it (**caller** mode), then plug the flow's URL
into any stream as its source or target.
## Authentication
Every request needs your API key in the `x-api-key` header. You can find your
API key(s) in the API section of the Camb.ai studio.
```bash theme={null}
curl -H "x-api-key: YOUR_API_KEY" "https://client.camb.ai/apis/stream/1234"
```
## Endpoints
| Endpoint | Purpose |
| ---------------------------------------------- | --------------------------------------- |
| [`POST /stream`](create-new-stream) | Create a stream |
| [`GET /stream/{stream_id}`](get-stream-status) | Get stream status |
| [`PATCH /stream/{stream_id}`](update-stream) | Update a stream / toggle dubbing |
| [`DELETE /stream/{stream_id}`](delete-stream) | Terminate a running or scheduled stream |
| [`POST /stream/probe/`](probe-stream) | Inspect a source |
| [`POST /flows`](create-flow) | Create an SRT flow |
| [`GET /flows`](list-flows) | List SRT flows |
| [`GET /flows/{flow_id}`](get-flow) | Get an SRT flow |
| [`PATCH /flows/{flow_id}`](update-flow) | Update an SRT flow |
| [`DELETE /flows/{flow_id}`](delete-flow) | Delete an SRT flow |
# Probe a Source Stream
Source: https://docs.camb.ai/api-reference/endpoint/streaming/probe-stream
post /stream/probe/
Inspect a source stream and list its video, audio, and data tracks before creating a live stream.
## Overview
A preflight check that connects to a source URL and reports the tracks it
carries, without creating anything. Use it to:
* Verify the source is reachable before scheduling a stream.
* Find the right audio track for `audio_selections[].source`.
* Check for data tracks such as SCTE-35 ad markers.
SRT sources are supported today; RTMP and HLS ingest are coming soon. Note
the trailing slash in the path: `POST /stream/probe/`.
## Example request
```bash cURL theme={null}
curl -X POST "https://client.camb.ai/apis/stream/probe/" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "srt://ingest.example.com:9000",
"passphrase": "my-secret-passphrase",
"stream_id": "live/primary"
}'
```
```python Python theme={null}
import requests
payload = {
"url": "srt://ingest.example.com:9000",
# Only needed if the source is encrypted / requires a streamid:
"passphrase": "my-secret-passphrase",
"stream_id": "live/primary",
}
response = requests.post(
"https://client.camb.ai/apis/stream/probe/",
headers={"x-api-key": "YOUR_API_KEY"},
json=payload,
)
response.raise_for_status()
print(response.json())
```
A reachable source returns its tracks:
```json Response theme={null}
{
"video_streams": [
{
"index": 0,
"codec_name": "h264",
"width": 1920,
"height": 1080,
"frame_rate": "25/1"
}
],
"audio_streams": [
{
"index": 1,
"codec_name": "aac",
"sample_rate": 48000,
"channels": 2,
"channel_layout": "stereo",
"tags": { "language": "eng" }
}
],
"data_streams": []
}
```
## From probe to create
Pick the audio track to process and reference it in your create payload's
`audio_selections`. Selectors count within a track type, so the first audio
track is `a:0` regardless of its overall index:
```json theme={null}
{
"audio_selections": [
{ "id": "commentary", "source": "a:0", "source_language": 1 }
]
}
```
If you are unsure which track carries speech, start with `$first_audio`.
## Errors
* `422` - Validation error, or the source could not be reached.
## Related endpoints
* [Create a Stream](create-new-stream)
* [Get Stream Status](get-stream-status)
# Update an SRT Flow
Source: https://docs.camb.ai/api-reference/endpoint/streaming/update-flow
patch /flows/{flow_id}
Rename a stream flow or bring its endpoint online or offline.
## Overview
Updates a flow. Only `label` and `active` can be changed. To change a flow's
mode, URLs, or failover setup, delete it and create a new one.
Setting `active` controls whether the flow's SRT endpoint is online. Inactive
flows keep their URLs and key, so you can take an endpoint offline between
events without reconfiguring your encoders.
```bash cURL theme={null}
curl -X PATCH "https://client.camb.ai/apis/flows/42" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "active": false }'
```
```python Python theme={null}
import requests
response = requests.patch(
"https://client.camb.ai/apis/flows/42",
headers={"x-api-key": "YOUR_API_KEY"},
json={"active": False},
)
response.raise_for_status()
print(response.json())
```
## Errors
* `404` - No flow with this ID belongs to your team.
* `422` - Validation error (e.g. a `label` already used by another of your team's flows).
## Related endpoints
* [Create an SRT Flow](create-flow)
* [Get an SRT Flow](get-flow)
* [Delete an SRT Flow](delete-flow)
# Update a Stream
Source: https://docs.camb.ai/api-reference/endpoint/streaming/update-stream
patch /stream/{stream_id}
Update a stream's configuration or apply live adjustments, including turning dubbing on and off, without recreating it.
## Overview
Partially updates an existing stream. Send only the fields you want to change.
Updates are allowed while the stream is scheduled, setting up, or started.
There are two kinds of changes:
* **Configuration updates** - rescheduling, replacing voices or dictionaries,
and adding or modifying audio selections, profiles, pipelines, and targets.
These are persisted into the stream configuration.
* **Live pipeline patches** (`pipeline_patches`) - runtime-only adjustments to
a running stream: turn dubbing on or off, adjust the dubbing mix, or nudge
audio/video sync. These take effect within seconds and are not persisted.
List fields that carry `id`s (`audio_selections`, `processing_profiles`,
`encoding_profiles`, `pipelines`, `target_streams`) are **merged by `id`**:
entries you send are added or replaced as a whole, and existing entries are
never removed.
You can paste a full JSON body into the **Try it** form and the fields fill
in automatically - copy any example below as a starting point.
## Turning dubbing on and off
Set `dubbing_enabled` on a pipeline patch. With `false`, dubbing pauses and
the original audio passes through; with `true`, dubbing resumes.
```bash cURL (pause dubbing) theme={null}
curl -X PATCH "https://client.camb.ai/apis/stream/1234" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"pipeline_patches": [
{ "pipeline_id": "spanish", "dubbing_enabled": false }
]
}'
```
```python Python (reschedule) theme={null}
import requests
payload = {
"start_time": "2026-08-01T11:00:00Z",
"end_time": "2026-08-01T13:00:00Z",
"timezone": "UTC",
}
response = requests.patch(
"https://client.camb.ai/apis/stream/1234",
headers={"x-api-key": "YOUR_API_KEY"},
json=payload,
)
response.raise_for_status()
print(response.json())
```
```python Python (adjust the live mix) theme={null}
import requests
payload = {
"pipeline_patches": [
{
"pipeline_id": "spanish",
"mixing": {
"original_audio_gain": 0.1,
"background_audio_gain": 0.8,
},
}
]
}
response = requests.patch(
"https://client.camb.ai/apis/stream/1234",
headers={"x-api-key": "YOUR_API_KEY"},
json=payload,
)
response.raise_for_status()
print(response.json())
```
## Common updates
| Goal | Fields to send |
| ----------------------------- | ----------------------------------------------------------------------- |
| Pause / resume dubbing | `pipeline_patches[].dubbing_enabled` |
| Adjust the dubbing mix live | `pipeline_patches[].mixing` gains (0.0–1.0) |
| Fix audio/video sync live | `pipeline_patches[].avsync.delay` (−2.0 to 2.0 s) |
| Reschedule | `start_time`, `end_time`, `timezone` |
| Change voices or dictionaries | `voices`, `dictionaries` |
| Add a target language | a new entry in `pipelines` (and its target) |
| Add or repoint an output | `target_streams` entry with the same `id` (replace) or a new `id` (add) |
## Errors
* `400` - The stream has already finished and can no longer be updated.
* `404` - No stream with this ID belongs to your team.
* `422` - Validation error: unknown `pipeline_id`, an `id` reference that
doesn't resolve, or times without a matching `timezone`.
## Related endpoints
* [Create a Stream](create-new-stream)
* [Get Stream Status](get-stream-status)
* [Delete a Stream](delete-stream)
# Use a Stream Template
Source: https://docs.camb.ai/api-reference/endpoint/streaming/use-template
get /stream/templates/{template_id}/payload
Retrieve a template's stream creation payload, ready to post as a new stream.
## Overview
Returns the stream creation payload the template was saved from: the exact
configuration of that stream, including its source, audio selections,
processing profiles, pipelines and targets.
The returned payload is compatible with the
[Create Stream](create-new-stream) request body. Its `start_time` and
`end_time` are the original stream's schedule and will be in the past, so set
them to your new broadcast window before creating the stream.
Templates are scoped to your workspace: requesting a template that belongs to
another workspace returns `404`.
```bash cURL theme={null}
curl -X GET "https://client.camb.ai/apis/stream/templates/12/payload" \
-H "x-api-key: YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.get(
"https://client.camb.ai/apis/stream/templates/12/payload",
headers={"x-api-key": "YOUR_API_KEY"},
)
response.raise_for_status()
payload = response.json()["payload"]
# Reschedule, then create a new stream from the template.
payload["start_time"] = "2026-08-15T18:45:00+02:00"
payload["end_time"] = "2026-08-15T21:00:00+02:00"
created = requests.post(
"https://client.camb.ai/apis/stream",
headers={"x-api-key": "YOUR_API_KEY"},
json=payload,
)
created.raise_for_status()
print(created.json())
```
```json Response theme={null}
{
"payload": {
"name": "Matchday 3: home fixture",
"source_stream": {
"id": "stadium_feed",
"url": "srt://ingest.example.com:9000",
"category": 2
},
"audio_selections": [
{
"id": "commentary",
"source": "$first_audio",
"source_language": 1
}
],
"processing_profiles": [
{
"id": "full_dub",
"demixing": "fast_model",
"transcribing": "fast_model",
"translating": "best_model",
"revoicing": "fast_model"
}
],
"pipelines": [
{
"id": "spanish",
"audio_selection": "commentary",
"profile": "full_dub",
"outputs": [
{ "id": "audio_es", "kind": "audio", "language": 37 },
{ "id": "subtitle_es", "kind": "subtitle", "language": 37 }
]
}
],
"target_streams": [
{
"id": "delivery",
"type": 1,
"url": "srt://delivery.example.com:9100",
"inputs": [{ "asset_id": "audio_es" }]
}
],
"start_time": "2026-08-01T18:45:00+02:00",
"end_time": "2026-08-01T21:00:00+02:00",
"timezone": "Europe/Madrid"
}
}
```
## Related endpoints
* [List Stream Templates](list-templates)
* [Create Stream](create-new-stream)
# Update Translation for a Term in Dictionary
Source: https://docs.camb.ai/api-reference/endpoint/update-term-in-dictionary
put /dictionaries/term/{dictionary_id}/{term_id}
Updates existing translations for a specific term within a dictionary, allowing you to refine translation accuracy, add new language variants, or correct linguistic content as your understanding evolves.
This endpoint represents one of the most nuanced and powerful operations in dictionary management - the ability to refine and improve existing translations after they've been established. Unlike creating new terms or adding entirely new content, updating translations acknowledges that language is living and evolving, and that our understanding of how concepts translate across cultures deepens over time.
## Understanding the Evolution of Translation Quality
The need to update translations arises from several important realities of multilingual content management. Languages themselves evolve, with new terms entering common usage while others become obsolete. Technical domains introduce specialized vocabulary that requires increasingly precise translations as understanding deepens. Cultural contexts shift, making some translations more or less appropriate over time.
## Quality Assurance in Translation Updates
Updating translations carries inherent responsibilities around quality assurance that extend beyond technical correctness. When you modify existing translations, you're potentially affecting every user and system that depends on that linguistic mapping. This influence requires thoughtful consideration of how changes might impact existing workflows, cached content, or user expectations.
## Integration Strategies for Translation Management
Consider implementing interfaces that help users understand the context and impact of proposed translation changes. Showing how current translations are being used, what alternatives exist, or how changes might affect related terms helps users make informed decisions about when updates truly improve linguistic resources versus when they might cause unintended disruption.
# Live Transcription (Websocket)
Source: https://docs.camb.ai/api-reference/websockets/listen
Stream raw audio to CAMB over a single WebSocket and receive cumulative interim transcripts, word-level timing, and typed events.
**Beta.** The live transcription WebSocket is generally available for testing but the schema, event shape, and error codes may change in backwards-incompatible ways before GA. Pin to the SDK versions you test against.
## What you get back
After connect, the server emits a single `Ready` event, then streams `Results` messages as your audio is consumed. Each `Results` carries the **cumulative** transcript for the current utterance — replace your in-progress UI state with it rather than concatenating.
The `is_final` flag tells interim refinements (`false`) apart from the frame that finalizes an utterance (`true`). After a final, **the next `Results` starts a brand-new utterance from an empty string** — so if you only ever overwrite your UI with the latest `transcript`, each new utterance erases the previous one. Show the interim frames as a live preview, then commit the text when `is_final` is `true` (the server also emits an `UtteranceEnd` boundary marker around the same point). Word-level timing (`channel.alternatives[0].words`, each entry with `word`/`start`/`end`/`confidence`) is populated only on the **final** frame (`is_final: true`); interim frames carry an empty `words` array. The `UtteranceEnd` marker also reports `last_word_end`. When the client stops sending audio, the connection closes cleanly with WebSocket close code `1000`.
## Supported source languages
Pass any of the codes below as the `language` query parameter, or omit it to default to `en-us`. You can also pass the Languages enum name (`EN_US`) or its numeric ID. The model performs automatic language detection regardless of the value passed.
| Code | Language |
| :--------------- | :----------------------------------------------- |
| `en-us` | English (United States) |
| `af-za` | Afrikaans (South Africa) |
| `am-et` | Amharic (Ethiopia) |
| `ar-ae` | Arabic (United Arab Emirates) |
| `ar-bh` | Arabic (Bahrain) |
| `ar-dz` | Arabic (Algeria) |
| `ar-eg` | Arabic (Egypt) |
| `ar-iq` | Arabic (Iraq) |
| `ar-jo` | Arabic (Jordan) |
| `ar-kw` | Arabic (Kuwait) |
| `ar-lb` | Arabic (Lebanon) |
| `ar-ly` | Arabic (Libya) |
| `ar-ma` | Arabic (Morocco) |
| `ar-om` | Arabic (Oman) |
| `ar-qa` | Arabic (Qatar) |
| `ar-sa` | Arabic (Saudi Arabia) |
| `ar-sy` | Arabic (Syria) |
| `ar-tn` | Arabic (Tunisia) |
| `ar-ye` | Arabic (Yemen) |
| `az-az` | Azerbaijani (Latin, Azerbaijan) |
| `bg-bg` | Bulgarian (Bulgaria) |
| `bn-bd` | Bangla (Bangladesh) |
| `bn-in` | Bengali (India) |
| `bs-ba` | Bosnian (Bosnia And Herzegovina) |
| `ca-es` | Catalan |
| `cs-cz` | Czech (Czechia) |
| `cy-gb` | Welsh (United Kingdom) |
| `da-dk` | Danish (Denmark) |
| `de-at` | German (Austria) |
| `de-ch` | German (Switzerland) |
| `de-de` | German (Germany) |
| `el-gr` | Greek (Greece) |
| `en-au` | English (Australia) |
| `en-ca` | English (Canada) |
| `en-gb` | English (United Kingdom) |
| `en-hk` | English (Hong Kong Sar) |
| `en-ie` | English (Ireland) |
| `en-in` | English (India) |
| `en-ke` | English (Kenya) |
| `en-ng` | English (Nigeria) |
| `en-nz` | English (New Zealand) |
| `en-ph` | English (Philippines) |
| `en-sg` | English (Singapore) |
| `en-tz` | English (Tanzania) |
| `en-za` | English (South Africa) |
| `es-ar` | Spanish (Argentina) |
| `es-bo` | Spanish (Bolivia) |
| `es-cl` | Spanish (Chile) |
| `es-co` | Spanish (Colombia) |
| `es-cr` | Spanish (Costa Rica) |
| `es-cu` | Spanish (Cuba) |
| `es-do` | Spanish (Dominican Republic) |
| `es-ec` | Spanish (Ecuador) |
| `es-es` | Spanish (Spain) |
| `es-gq` | Spanish (Equatorial Guinea) |
| `es-gt` | Spanish (Guatemala) |
| `es-hn` | Spanish (Honduras) |
| `es-mx` | Spanish (Mexico) |
| `es-ni` | Spanish (Nicaragua) |
| `es-pa` | Spanish (Panama) |
| `es-pe` | Spanish (Peru) |
| `es-pr` | Spanish (Puerto Rico) |
| `es-py` | Spanish (Paraguay) |
| `es-sv` | Spanish (El Salvador) |
| `es-us` | Spanish (United States) |
| `es-uy` | Spanish (Uruguay) |
| `es-ve` | Spanish (Venezuela) |
| `et-ee` | Estonian (Estonia) |
| `eu-es` | Basque |
| `fa-ir` | Persian (Iran) |
| `fi-fi` | Finnish (Finland) |
| `fr-be` | French (Belgium) |
| `fr-ca` | French (Canada) |
| `fr-ch` | French (Switzerland) |
| `fr-fr` | French (France) |
| `gl-es` | Galician |
| `gu-in` | Gujarati (India) |
| `he-il` | Hebrew (Israel) |
| `hi-in` | Hindi (India) |
| `hr-hr` | Croatian (Croatia) |
| `hu-hu` | Hungarian (Hungary) |
| `hy-am` | Armenian (Armenia) |
| `id-id` | Indonesian (Indonesia) |
| `is-is` | Icelandic (Iceland) |
| `it-it` | Italian (Italy) |
| `ja-jp` | Japanese (Japan) |
| `ka-ge` | Georgian (Georgia) |
| `kk-kz` | Kazakh (Kazakhstan) |
| `km-kh` | Khmer (Cambodia) |
| `kn-in` | Kannada (India) |
| `ko-kr` | Korean (Korea) |
| `lo-la` | Lao (Laos) |
| `lt-lt` | Lithuanian (Lithuania) |
| `lv-lv` | Latvian (Latvia) |
| `mk-mk` | Macedonian (North Macedonia) |
| `ml-in` | Malayalam (India) |
| `mn-mn` | Mongolian (Mongolia) |
| `mr-in` | Marathi (India) |
| `ms-my` | Malay (Malaysia) |
| `mt-mt` | Maltese (Malta) |
| `my-mm` | Burmese (Myanmar) |
| `nb-no` | Norwegian (Bokmål, Norway) |
| `ne-np` | Nepali (Nepal) |
| `nl-be` | Dutch (Belgium) |
| `nl-nl` | Dutch (Netherlands) |
| `pa-in` | Punjabi (India) |
| `pl-pl` | Polish (Poland) |
| `ps-af` | Pashto (Afghanistan) |
| `pt-br` | Portuguese (Brazil) |
| `pt-pt` | Portuguese (Portugal) |
| `ro-ro` | Romanian (Romania) |
| `ru-ru` | Russian (Russia) |
| `si-lk` | Sinhala (Sri Lanka) |
| `sk-sk` | Slovak (Slovakia) |
| `sl-si` | Slovenian (Slovenia) |
| `so-so` | Somali (Somalia) |
| `sq-al` | Albanian (Albania) |
| `sr-rs` | Serbian (Cyrillic, Serbia) |
| `su-id` | Sundanese (Indonesia) |
| `sv-se` | Swedish (Sweden) |
| `sw-ke` | Swahili (Kenya) |
| `sw-tz` | Swahili (Tanzania) |
| `ta-in` | Tamil (India) |
| `ta-lk` | Tamil (Sri Lanka) |
| `ta-my` | Tamil (Malaysia) |
| `ta-sg` | Tamil (Singapore) |
| `te-in` | Telugu (India) |
| `th-th` | Thai (Thailand) |
| `tl-ph` | Tagalog (Philippines) |
| `tr-tr` | Turkish (Turkey) |
| `uk-ua` | Ukrainian (Ukraine) |
| `ur-in` | Urdu (India) |
| `ur-pk` | Urdu (Pakistan) |
| `uz-uz` | Uzbek (Latin, Uzbekistan) |
| `vi-vn` | Vietnamese (Vietnam) |
| `zh-cn` | Chinese (Mandarin, Simplified) |
| `zh-cn-henan` | Chinese (Zhongyuan Mandarin Henan, Simplified) |
| `zh-cn-liaoning` | Chinese (Northeastern Mandarin, Simplified) |
| `zh-cn-shaanxi` | Chinese (Zhongyuan Mandarin Shaanxi, Simplified) |
| `zh-cn-shandong` | Chinese (Jilu Mandarin, Simplified) |
| `zh-cn-sichuan` | Chinese (Southwestern Mandarin, Simplified) |
| `zh-hk` | Chinese (Cantonese, Traditional) |
| `zh-tw` | Chinese (Taiwanese Mandarin, Traditional) |
## Sample Testing Script
The CAMB SDKs wrap the protocol below behind a typed event dispatcher. The snippets here stream a WAV file at real-time pace so the server sees arrival patterns equivalent to a live microphone capture. For mic input, swap `FileAudioSource(...)` for `Microphone(...)` (Python) or `Microphone.fromBrowser` / `Microphone.fromNode` (TypeScript) — see the [Live Transcription tutorial](/tutorials/live-transcription-with-sdk).
```python Python theme={null}
# pip install camb-sdk
import asyncio
import os
import wave
from camb.client import CambAI
from camb.live_transcription import FileAudioSource, ServerMessageType
async def main(audio_path: str = "sample.wav") -> None:
with wave.open(audio_path, "rb") as wf:
sample_rate, channels = wf.getframerate(), wf.getnchannels()
client = CambAI(api_key=os.environ["CAMB_API_KEY"])
session = await client.live_transcription.connect(
model="boli-v5",
language="en-us",
encoding="linear16",
sample_rate=sample_rate,
channels=channels,
)
@session.on(ServerMessageType.READY)
def _(_): print("Ready: streaming audio...")
@session.on(ServerMessageType.RESULTS)
def _(msg):
text = msg.transcript.strip()
if not text:
return
# Interim frames print as they arrive; commit the final on its own
# line so the next utterance doesn't overwrite it.
if not msg.is_final:
print(f"[Interim] {text}\n", end="", flush=True)
else:
print(f"\r\033[K{text}\n", end="", flush=True)
@session.on(ServerMessageType.CLOSED)
def _(info): print(f"\nClosed: code={info.code}")
async with session:
await session.stream_audio(FileAudioSource(audio_path, real_time=True))
asyncio.run(main())
```
```typescript TypeScript theme={null}
// npm install @camb-ai/sdk ws
import fs from "node:fs";
import { CambClient, ServerMessageType } from "@camb-ai/sdk";
// Minimal WAV reader — returns { sampleRate, channels, bitsPerSample, pcm }.
function readWav(path: string) {
const buf = fs.readFileSync(path);
let o = 12, sr = 0, ch = 0, bps = 0, dStart = -1, dLen = 0;
while (o < buf.length - 8) {
const id = buf.toString("ascii", o, o + 4);
const size = buf.readUInt32LE(o + 4);
if (id === "fmt ") { ch = buf.readUInt16LE(o + 10); sr = buf.readUInt32LE(o + 12); bps = buf.readUInt16LE(o + 22); }
else if (id === "data") { dStart = o + 8; dLen = size; break; }
o += 8 + size;
}
return { sampleRate: sr, channels: ch, bitsPerSample: bps, pcm: buf.subarray(dStart, dStart + dLen) };
}
const { sampleRate, channels, bitsPerSample, pcm } = readWav("sample.wav");
const client = new CambClient({ apiKey: process.env.CAMB_API_KEY! });
const session = await client.liveTranscription.connect({
model: "boli-v5",
language: "en-us",
encoding: "linear16",
sampleRate,
channels,
});
session.on(ServerMessageType.Ready, () => console.log("Ready: streaming audio..."));
session.on(ServerMessageType.Results, (m) => {
const text = m.transcript.trim();
if (!text) return;
// Interim frames print as they arrive; commit the final on its own line.
if (!m.isFinal) process.stdout.write(`[Interim] ${text}\n`);
else process.stdout.write(`\r\x1b[K${text}\n`);
});
session.on(ServerMessageType.Closed, (i) => console.log(`\nClosed: code=${i.code}`));
// Real-time-paced send so the server sees live arrival patterns.
const bytesPerSec = sampleRate * channels * (bitsPerSample / 8);
const chunk = Math.floor(bytesPerSec / 10); // 100 ms
const t0 = Date.now();
let sent = 0;
for (let i = 0; i < pcm.length; i += chunk) {
await session.sendAudio(pcm.subarray(i, i + chunk));
sent += chunk;
const drift = (sent / bytesPerSec) * 1000 - (Date.now() - t0);
if (drift > 0) await new Promise((r) => setTimeout(r, drift));
}
await session.close();
await session.waitUntilClosed();
```
### Timeout
The Live Transcription API has an internal timeout of 1 hour. Please add retries to handle/create further connections.
### Raw protocol (no SDK)
If you cannot use the SDKs, the wire protocol is small enough to drive directly. Open `wss://realtime.camb.ai/streaming-transcription/listen?...` with the `x-api-key` header, send binary PCM frames matching the `encoding` / `sample_rate` / `channels` query string, optionally send `{"type":"KeepAlive"}` during silence, and finish with `{"type":"CloseStream"}`. The server returns `{"type":"Ready"}` once, then `{"type":"Results", ...}` frames carrying the cumulative transcript (`"is_final": false` for interim refinements, `true` on the frame that finalizes each utterance), and closes with WebSocket code `1000` on a clean shutdown.
# Live TTS (WebSocket)
Source: https://docs.camb.ai/api-reference/websockets/live-tts
Stream text in, receive synthesized speech audio + optional word-level timestamps in real time over a single WebSocket connection.
Bidirectional WebSocket endpoint for real-time text-to-speech. Push text as you have it; receive audio as it's synthesized, in strict segment order. Designed for live captions, narration over streaming LLM output, interactive voice apps — anywhere you want playback to start before the writer is finished writing.
```
wss://client.camb.ai/apis/live-tts/ws
```
Authenticate with your CambAI API key via the `x-api-key` header (or `?api_key=...` query parameter for clients that can't set headers).
## Quickstart
A complete, copy-pasteable client. Connect → configure → stream text → write the audio to a file.
```python expandable theme={null}
import asyncio
import json
import websockets
async def synthesize(api_key: str, text: str, out_path: str = "out.mp3") -> None:
url = "wss://client.camb.ai/apis/live-tts/ws"
async with websockets.connect(
url,
additional_headers=[("x-api-key", api_key)],
) as ws:
# 1. First frame: session config.
await ws.send(json.dumps({
"type": "session.start",
"voice_id": 6460,
"language": "en-us",
"output_format": "mp3",
"word_timestamps": True,
}))
# 2. Server confirms with session.ready.
ready = json.loads(await ws.recv())
assert ready["type"] == "session.ready", ready
print(f"session {ready['session_id']} run_id={ready['run_id']}")
# 3. Stream text. You can call text.chunk many times; the server
# segments based on content (and on a 1s idle flush).
await ws.send(json.dumps({"type": "text.chunk", "text": text}))
await ws.send(json.dumps({"type": "text.done"}))
# 4. Receive ordered audio + json frames until the session ends.
with open(out_path, "wb") as f:
async for msg in ws:
if isinstance(msg, bytes):
f.write(msg)
continue
frame = json.loads(msg)
kind = frame["type"]
if kind == "segment.start":
print(f" segment {frame['segment_id']}: {frame['text']!r}")
for w in frame.get("word_timestamps", []):
print(f" {w['start']:6.2f}s → {w['end']:6.2f}s {w['word']}")
elif kind == "segment.skipped":
print(f" ! skipped segment {frame['segment_id']}: {frame['text']!r}")
elif kind == "session.done":
print("done")
break
elif kind == "session.error":
raise RuntimeError(frame["error"])
asyncio.run(synthesize(
api_key="your-camb-api-key",
text="Hello, world. This is a streaming text-to-speech demo.",
))
```
That's the whole integration surface. Everything below is reference for the four message types you'll exchange.
## Integration in 4 steps
```python theme={null}
async with websockets.connect(
"wss://client.camb.ai/apis/live-tts/ws",
additional_headers=[("x-api-key", "your-camb-api-key")],
) as ws:
...
```
Missing or invalid key → server closes with code `4401`.
```json theme={null}
{
"type": "session.start",
"voice_id": 6460,
"language": "en-us",
"output_format": "mp3",
"word_timestamps": true,
"idle_timeout": 1.0,
"enhance_named_entities_pronunciation": false,
"apply_enhancement": null,
"enhance_reference_audio_quality": false,
"maintain_source_accent": false,
"speaking_rate": null,
"inference_steps": null
}
```
`voice_id` is the only required field — everything else has a sensible default. The tuning knobs mirror the regular `POST /tts-stream` API one-for-one (`enhance_named_entities_pronunciation`, `apply_enhancement`, `enhance_reference_audio_quality`, `maintain_source_accent`, `speaking_rate`), so you can port a working `/tts-stream` payload directly. See the full reference at the top of the page for types and defaults.
Wait for the `session.ready` reply (carries `session_id` and `run_id`). A malformed first frame, forbidden voice, or unsupported language → `session.error` then close `4400`.
```json theme={null}
{"type": "text.chunk", "text": "Hello, "}
{"type": "text.chunk", "text": "world."}
```
Push as fast or as slowly as you like. The server segments by content (sentence boundaries), and **idle-flushes after `idle_timeout` seconds of silence** (default `1.0`) — so for live use cases (LLM token stream, transcribed mic input) you don't need to send `text.done` until the session is truly over.
`idle_timeout` is only a *fallback* flush for trailing fragments without a boundary. **A complete sentence (terminal punctuation, paragraph break, etc.) is flushed immediately — it never waits on `idle_timeout`.** Bump the value on `session.start` (e.g. `2.5`) if your producer routinely stalls *mid*-sentence — slower LLMs, token-level jitter — to avoid splitting one sentence across two segments.
**Slow producers fragment sentences.** If your LLM (or other source) is not producing text fast enough to land consecutive chunks within `idle_timeout` (default `1s`), each chunk will be flushed as its own segment — even if together they would have formed a single sentence. The result is choppier audio and prosody that resets at each fragment boundary. Raise `idle_timeout` to cover the worst-case gap between your producer's tokens.
For each segment N, the server emits, in order:
```
segment.start N → → segment.done N
```
Segment N's frames are completely emitted before any of segment N+1's, even though synthesis runs concurrently behind the scenes. Concatenate the binary frames per `segment_id` and you have playable audio.
When everything is done you'll receive `session.done`, followed by a clean close.
## Common patterns
### Stream from an LLM
Push tokens straight from the model. Don't call `text.done` — let the idle flush handle in-flight buffering, then close when the LLM is done.
```python theme={null}
async for token in llm_stream():
await ws.send(json.dumps({"type": "text.chunk", "text": token}))
# LLM finished; flush any tail and end cleanly.
await ws.send(json.dumps({"type": "text.done"}))
```
### Play audio while it's still synthesizing
Hand each segment to your player as soon as `segment.done` arrives:
```python theme={null}
buffers: dict[int, bytearray] = {}
current_segment: int | None = None
async for msg in ws:
if isinstance(msg, bytes):
if current_segment is not None:
buffers.setdefault(current_segment, bytearray()).extend(msg)
continue
frame = json.loads(msg)
if frame["type"] == "segment.start":
current_segment = frame["segment_id"]
elif frame["type"] == "segment.done":
sid = frame["segment_id"]
player.enqueue(bytes(buffers.pop(sid))) # play this segment
current_segment = None
elif frame["type"] == "session.done":
break
```
### Recover from a skipped segment
`segment.skipped` means TTS retries (3 by default, exponential backoff) were exhausted for that segment. The session keeps running — re-send the text in a new `text.chunk` if you need the audio:
```python theme={null}
if frame["type"] == "segment.skipped":
await ws.send(json.dumps({"type": "text.chunk", "text": frame["text"]}))
```
### Word-level timestamps
Set `"word_timestamps": true` in `session.start`. When resolution succeeds, `segment.start` carries a `word_timestamps` array:
```json theme={null}
{
"type": "segment.start",
"segment_id": 0,
"text": "Hello, world.",
"word_timestamps": [
{"word": "Hello", "start": 0.04, "end": 0.32},
{"word": "world", "start": 0.38, "end": 0.71}
]
}
```
Word-timestamp failures (timeout, 5xx, network) are silently swallowed; the segment is still delivered without the `word_timestamps` field. Treat it as **best-effort** — don't block playback on it.
## Reference
The AsyncAPI spec above documents every message type and field. Quick lookup:
### Close codes
| Code | Reason |
| :----- | :--------------------------------------------------------- |
| `4400` | Bad first frame, forbidden voice, or unsupported language. |
| `4401` | Missing or invalid API key. |
| `4402` | Insufficient credits. |
### Auth & billing
* API key auth is identical to the rest of `/apis/*`.
* A `TTS_API` Run is created on `session.start`; its `run_id` is in `session.ready` and can be queried later via the standard run endpoints.
* **Credits are deducted per segment**, immediately before that segment is synthesized. If you run out mid-session, the server emits a single `session.error` and closes with `4402`.
### Voice & language
Voice access uses the same rules as `/tts-stream`. The session is pinned to the `mars-8.1-flash-beta` speech model — see the [streaming TTS docs](/api-reference/endpoint/create-tts-stream) for the supported BCP-47 locales. For best results, supply a reference voice in the same language/accent as `language`.
### Server-side TTS retries
`ConnectionError` / `TimeoutError` / `OSError` / `aiohttp.ClientError` against the underlying TTS engine trigger up to 3 retries per segment with exponential backoff. On exhaustion the segment becomes `segment.skipped` (see *Recover from a skipped segment* above) and the rest of the session continues normally.
# Realtime Speech To Speech
Source: https://docs.camb.ai/api-reference/websockets/realtime
Stream microphone audio into a realtime translation session and receive transcripts, translated text, and translated audio.
**Beta.** The Speech to Speech WebSocket is generally available for testing but session events, configuration, and audio formats may change in backwards-incompatible ways before GA.
Bidirectional WebSocket endpoint for real-time speech translation. This endpoint is served by `realtime-api-server` at `wss://realtime.camb.ai/v1/realtime`, separate from the `/apis/live-tts/ws` and `/streaming-transcription/listen` WebSocket endpoints.
```http theme={null}
GET /v1/realtime
Host: realtime.camb.ai
x-api-key:
```
Sessions run in one of two modes, selected with the `mode` query parameter or the `mode` field of the first `session.update`. `fast` (the default) accepts audio almost immediately and translates with the lowest latency, but supports fewer languages. `slow` supports the full language list and translates more accurately, at the cost of a 30s+ cold boot before the session is ready.
`mode` replaced a `model` parameter that took engine codenames. Both are still accepted — `iris` resolves to `fast`, and `lilac`/`violet`/`orchid` to `slow` — so existing integrations keep working while you migrate.
Authenticate with the `x-api-key` WebSocket request header. If your client cannot set WebSocket headers, send credentials in the first `session.update` event instead.
## Quickstart
Use the **SDK** (Python or TypeScript) — it handles the session lifecycle (including the `session.starting` cold-boot wait), surfaces the server's binary audio frames as typed audio events, and exposes typed events. Input and output audio are PCM16, mono, 24 kHz. The example below streams a WAV file and writes the translated speech to another WAV.
```python Python theme={null}
import asyncio
import os
import wave
from camb.client import CambAI
from camb.realtime import ServerEventType
from camb.live_transcription import FileAudioSource
async def main():
client = CambAI(api_key=os.environ["CAMB_API_KEY"])
session = await client.realtime.connect(
source_language="en-us",
target_language="de-de",
)
out_audio = bytearray()
@session.on(ServerEventType.TEXT_DONE)
def _(event):
print("translation:", event.text)
@session.on(ServerEventType.AUDIO_DELTA)
def _(event):
out_audio.extend(event.data) # raw PCM16 mono 24 kHz
async with session:
await session.wait_until_ready()
# Input WAV must be 16-bit PCM, mono, 24 kHz.
await session.stream_audio(FileAudioSource("input_24k_mono.wav", real_time=True))
with wave.open("translated.wav", "wb") as out:
out.setnchannels(1)
out.setsampwidth(2)
out.setframerate(24000)
out.writeframes(bytes(out_audio))
asyncio.run(main())
```
```typescript TypeScript theme={null}
import fs from "node:fs";
import { CambClient, RealtimeServerEventType } from "@camb-ai/sdk";
const client = new CambClient({ apiKey: process.env.CAMB_API_KEY });
const session = await client.realtime.connect({
sourceLanguage: "en-us",
targetLanguage: "de-de",
});
const outChunks = [];
let resolveDone;
const audioDone = new Promise((r) => (resolveDone = r));
session.on(RealtimeServerEventType.TextDone, (event) =>
console.log("translation:", event.text),
);
session.on(RealtimeServerEventType.AudioDelta, (event) =>
outChunks.push(Buffer.from(event.data)), // raw PCM16 mono 24 kHz
);
session.on(RealtimeServerEventType.AudioDone, () => resolveDone());
await session.waitUntilReady();
// Input WAV must be 16-bit PCM, mono, 24 kHz. This skips the standard 44-byte
// header and streams the PCM data at real-time pace in 100 ms slices.
const data = fs.readFileSync("input_24k_mono.wav").subarray(44);
const chunkSize = 24000 * 2 * 0.1;
for (let i = 0; i < data.length; i += chunkSize) {
await session.sendAudio(data.subarray(i, i + chunkSize));
await new Promise((r) => setTimeout(r, 100));
}
await Promise.race([audioDone, new Promise((r) => setTimeout(r, 30_000))]);
await session.close();
// Raw PCM16 mono 24 kHz; wrap in a WAV header to play it (see the tutorial).
fs.writeFileSync("translated.pcm", Buffer.concat(outChunks));
```
See the [Realtime Speech Translation tutorial](/tutorials/realtime-translation-with-sdk) for the microphone quickstart, the full event list, and configuration.
The sections below document the underlying wire protocol for reference (for example, if you are building a client in a language without an SDK).
## Integration in 4 steps
Connect to `wss://realtime.camb.ai/v1/realtime`. This endpoint is not under the `client.camb.ai/apis` namespace used by the other WebSocket API references.
```python theme={null}
async with websockets.connect(
"wss://realtime.camb.ai/v1/realtime",
additional_headers=[("x-api-key", "YOUR_API_KEY")],
) as ws:
...
```
The first WebSocket message must be a JSON `session.update` event. The server waits up to 10 seconds for it.
```json theme={null}
{
"type": "session.update",
"session": {
"source_language": "en-us",
"target_language": "de-de",
"output_modalities": ["text", "audio"]
}
}
```
The server responds with `session.created`, then `session.updated`.
Send microphone audio as base64-encoded bytes in `input_audio_buffer.append`. Only text WebSocket messages are parsed as realtime events.
```json theme={null}
{
"type": "input_audio_buffer.append",
"audio": ""
}
```
Each decoded audio payload can be up to 256 KiB.
Listen for transcript, translated text, and translated audio events. `response.text.delta` values are additive for the current response, and `response.audio.delta` contains base64-encoded synthesized audio bytes.
## Authentication
Prefer the WebSocket request header:
```http theme={null}
x-api-key:
```
The initial `session.update` event can also carry credentials:
```json API key auth theme={null}
{
"type": "session.update",
"session": {
"source_language": "en-us",
"target_language": "de-de",
"output_modalities": ["text", "audio"]
},
"auth": {
"api_key": ""
}
}
```
If both the request header and `auth` object are present, the request header credential is used.
## Reference
The AsyncAPI spec above documents every client and server event. Quick lookup:
### Session configuration
| Field | Type | Required | Notes |
| :------------------ | :-------- | :------- | :---------------------------------------------------------------------------------------------------- |
| `source_language` | string | Yes | Source language tag, for example `en-us`. Must be a [supported language](#supported-languages). |
| `target_language` | string | Yes | Target language tag, for example `de-de`. Must be a [supported language](#supported-languages). |
| `output_modalities` | string\[] | No | Defaults to `["text", "audio"]`. |
| `voice` | object | No | Output voice selection. Defaults to `{ "type": "default" }`. See [Voice selection](#voice-selection). |
### Voice selection
By default, translated speech is synthesized with a built-in voice for the target language. To synthesize the translation with one of your own cloned voices, include a `voice` object in the session configuration:
```json theme={null}
{
"type": "session.update",
"session": {
"source_language": "en-us",
"target_language": "de-de",
"output_modalities": ["text", "audio"],
"voice": { "type": "cloned", "voice_id": 147320 }
}
}
```
| Field | Type | Required | Notes |
| :--------- | :------ | :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | string | Yes | `"default"` to use the built-in voice, or `"cloned"` to use one of your voices. |
| `voice_id` | integer | When `type` is `"cloned"` | ID of a voice you own. Get it from [List Voices](/api-reference/endpoint/list-voices) or [Create Custom Voice](/api-reference/endpoint/create-custom-voice). |
The voice must belong to your account — stock/built-in voice IDs are rejected with an `error` event. Omitting `voice` (or sending `{ "type": "default" }`) uses the built-in voice. The resolved selection is echoed back in `session.created`.
If you use the SDK, pass `voice_id` (Python) or `voiceId` (TypeScript) to `realtime.connect()` and it builds this `voice` object for you:
```python Python theme={null}
session = await client.realtime.connect(
source_language="en-us",
target_language="de-de",
voice_id=147320,
)
```
```typescript TypeScript theme={null}
const session = await client.realtime.connect({
sourceLanguage: "en-us",
targetLanguage: "de-de",
voiceId: 147320,
});
```
For the most natural-sounding results, choose a voice whose reference
language matches your `target_language`. A large mismatch between the
voice's native language and the translation language can reduce clarity
and accent accuracy.
### Supported languages
`source_language` and `target_language` accept the BCP-47 tags below (case-insensitive). Pick any supported language as the source and any supported language as the target.
| Code | Language |
| :------ | :----------------------------- |
| `ar-ae` | Arabic (United Arab Emirates) |
| `ar-eg` | Arabic (Egypt) |
| `ar-sa` | Arabic (Saudi Arabia) |
| `de-de` | German (Germany) |
| `en-gb` | English (United Kingdom) |
| `en-us` | English (United States) |
| `es-es` | Spanish (Spain) |
| `fr-ca` | French (Canada) |
| `fr-fr` | French (France) |
| `hi-in` | Hindi (India) |
| `ja-jp` | Japanese (Japan) |
| `ko-kr` | Korean (Korea) |
| `pt-br` | Portuguese (Brazil) |
| `zh-cn` | Chinese (Mandarin, Simplified) |
### Client events
| Event | Support |
| :-------------------------- | :--------------------------------------------- |
| `session.update` | Required first message. |
| `input_audio_buffer.append` | Supported after activation. |
| `input_audio_buffer.clear` | Recognized but not supported; returns `error`. |
| `input_audio_buffer.commit` | Recognized but not supported; returns `error`. |
| `response.cancel` | Recognized but not supported; returns `error`. |
### Server events
| Event | Description |
| :------------------------------------------------------ | :----------------------------------------------------- |
| `session.created` | Session has been authorized, started, and activated. |
| `session.updated` | Active session configuration. |
| `conversation.item.input_audio_transcription.completed` | Completed user transcript. |
| `response.text.delta` | Additive translated text delta. |
| `response.text.done` | Final translated text. |
| `response.audio.delta` | Base64-encoded translated audio bytes. |
| `response.audio.done` | Current translated audio response is complete. |
| `error` | Unsupported recognized event or billing stop decision. |
### Limits
| Limit | Value |
| :------------------------------------------------------------ | :------------------------- |
| Initial `session.update` timeout | 10 seconds |
| Maximum client event text size | 1 MiB |
| Maximum decoded audio payload per `input_audio_buffer.append` | 256 KiB |
| Audio encoding in `input_audio_buffer.append.audio` | Base64-encoded audio bytes |
### Billing
Active sessions are charged in billing windows and finalized on close, failure, or billing stop. If billing stops a session, the server sends an `error` event whose `error.message` is the billing close reason, then ends the realtime loop.
# Choosing a Model
Source: https://docs.camb.ai/choosing-a-model
A guide to picking the right MARS 8 variant for your use case
The MARS 8 family has six model variants, each optimized for different trade-offs between **latency**, **quality**, **controllability**, and **deployment footprint**. Use this guide to find the best fit for your application.
## Quick Comparison
| | MARS-8.1-Flash-Beta | MARS-8.1-Pro-Beta | MARS-Flash | MARS-Pro | MARS-Instruct | MARS-Nano |
| --------------------------- | ----------------------------- | ----------------- | ---------- | ------------ | ---------------- | ------------ |
| **Parameters** | 600M | 600M | 600M | 600M | 1.2B | 50M |
| **TTFB** | Faster than MARS-8.1-Pro-Beta | 800 ms – 2 s | \~150 ms | 800 ms – 2 s | Higher (offline) | 500 ms – 2 s |
| **Real-time capable** | Yes | Yes | Yes | Yes | No | Yes |
| **Emotion/prosody control** | No | No | No | No | Yes | No |
| **On-device friendly** | No | No | No | No | No | Yes |
## Decision Flowchart
Start with the primary constraint of your application:
### 1. Do you want to evaluate the newest MARS 8.1 beta models?
**Yes - try [MARS-8.1-Flash-Beta](/models#mars-81-flash-beta-48khz) or [MARS-8.1-Pro-Beta](/models#mars-81-pro-beta-48khz).**
Use `speech_model: "mars-8.1-flash-beta"` when you want the same MARS 8.1 quality target with faster generation. Use `speech_model: "mars-8.1-pro-beta"` when you want to compare the newest Pro-quality model against `mars-pro`. These 8.1 models may perform much better for pronunciation, overall prosody, accent control, accent coverage, quality across different accents, and expressiveness with high-pitch reference voices.
Because these are beta models, validate them with your target voices, languages, accents, and formats before rolling them into production. For best results, your target language should use a reference voice in the same language and accent.
### 2. Do you need real-time, low-latency speech?
**Yes - use [MARS-Flash](/models#mars-flash-2205khz48khz).**
Flash is purpose-built for conversational AI. With TTFB as low as 150 ms, it handles agentic conversations, call center bots, and live assistants where every millisecond counts.
Choose Flash when:
* You're building a voice agent or assistant
* End-to-end latency is a hard requirement
* Speed and real-time responsiveness matter most
### 3. Do you need high-fidelity speech with voice and emotion transfer?
**Yes - use [MARS-Pro](/models#mars-pro-48khz).**
Pro offers balanced speed and fidelity, delivering the best overall performance when speed is not the primary constraint. It preserves speaker identity and emotion from reference audio, making it ideal for dubbing, audiobooks, and expressive media.
Choose Pro when:
* You need expressive, natural-sounding speech
* Real-time translation with voice transfer is required
* You can tolerate 800 ms – 2 s of latency
* Short or challenging reference audio is involved
### 4. Do you need fine-grained control over delivery style?
**Yes - use [MARS-Instruct](/models#mars-instruct-2205khz).**
Instruct gives you director-level control. You can independently adjust speaker identity, emotion, and prosody using either a reference audio sample or a text description (e.g., "warm and reassuring tone").
Choose Instruct when:
* You're producing content for TV, film, or post-production
* You need to guide emotion and delivery with text instructions
* Latency is not a concern (batch/offline workflows)
* You want to decouple speaker identity from speaking style
See the [Emotional Voice Control tutorial](/tutorials/emotional-voice-control) for examples of emotion tags, prosody control, and best practices.
### 5. Do you need to run TTS on-device?
**Yes - use [MARS-Nano](/models#mars-nano).**
At just 50M parameters, Nano runs in memory-constrained environments where cloud access isn't available or practical.
Choose Nano when:
* You're deploying on edge hardware or mobile devices
* Strict memory and compute budgets apply
* Cloud connectivity is unreliable or unavailable
## Common Scenarios
| Scenario | Recommended Model |
| --------------------------------------------------- | ------------------------- |
| Faster MARS 8.1 output with stronger accent quality | MARS-8.1-Flash-Beta |
| Evaluating the newest Pro-quality TTS output | MARS-8.1-Pro-Beta |
| Voice agent for customer support | MARS-Flash |
| Real-time language translation with voice cloning | MARS-Pro |
| Audiobook production | MARS-Pro |
| Movie dubbing with director-guided emotion | MARS-Instruct |
| Smart speaker / IoT device | MARS-Nano |
| Live conversational assistant | MARS-Flash |
| Post-production voice editing | MARS-Instruct |
| Offline batch TTS pipeline | MARS-Pro or MARS-Instruct |
## Still Not Sure?
* **Start with MARS-Pro** if you want the best balance of speed and fidelity without worrying about constraints.
* **Switch to Flash** if latency testing reveals Pro is too slow for your real-time pipeline.
* **Reach out on [Discord](https://discord.gg/hzXnxTxhFw)** if your use case doesn't fit neatly into one of these categories.
# Custom Cloud Providers
Source: https://docs.camb.ai/custom-cloud-providers
### A Compute-First Business Model
The status quo of "pay-per-character" API pricing eats margins as they scale. We are changing it. This is also ideal for enterprise use cases requiring strict data privacy, dedicated throughput, or custom model fine-tuning.
MARS 8 Series is available on following providers:
* Google Cloud Vertex AI
* AWS Bedrock
* Hugging face
* Baseten
* Modal
* Cerebrium
* Simplismart
* Replicate
For access contact [help@camb.ai](mailto:help@camb.ai)
## Routing Via Camb AI SDK
The Camb AI SDK directly supports routing Text-to-Speech generation requests to private or above custom deployments of the MARS model.
#### Baseten Deployment
Initialize the client with your API key and the specific model URL. [Baseten Provider Example](https://github.com/Camb-ai/cambai-python-sdk/blob/main/examples/baseten_provider_example.py)
Deployment Link: [https://app.baseten.co/deploy/mars8-flash](https://app.baseten.co/deploy/mars8-flash)
```python theme={null}
import base64
from camb.client import CambAI, save_stream_to_file
client = CambAI(
tts_provider="baseten",
provider_params={
"api_key": "YOUR_BASETEN_API_KEY",
"mars_pro_url": "https://model-xxxxxx.api.baseten.co/environments/production/predict"
}
)
def main():
response = client.text_to_speech.tts(
text="Hello World and my dear friends",
language="en-us",
speech_model="mars-flash",
request_options={
"additional_body_parameters": {
"reference_audio": base64.b64encode(open("audio.wav", "rb").read()).decode('utf-8'), # or a public signed url
"reference_language": "en-us" # required
},
"timeout_in_seconds": 300
}
)
save_stream_to_file(response, "tts_output.wav")
print("Success! Audio saved to tts_output.wav")
if __name__ == "__main__":
main()
```
### How it Works
1. The SDK bypasses standard Camb AI API endpoints.
2. It authenticates directly with Baseten using the provided API Key.
3. It streams generated audio directly from the model instance.
## Vertex AI Deployment
Support for Vertex AI is currently in progress.
#### Usage Example
```python theme={null}
client = CambAI(
tts_provider="vertex",
provider_params={
"project_id": "your-gcp-project-id",
"location": "us-central1"
}
)
```
# Authentication & API Keys
Source: https://docs.camb.ai/getting-started/authentication
Learn how to authenticate with the CAMB.AI API
All CAMB.AI API requests require authentication using an API key. This guide explains how to obtain and use your API key.
## Getting Your API Key
1. Go to [CAMB.AI Studio](https://studio.camb.ai)
2. Sign in or create an account
3. Navigate to your account settings
4. Generate or copy your API key
Keep your API key secure. Never expose it in client-side code or public repositories.
## Using Your API Key
Include your API key in the `x-api-key` header of every request.
### Header Format
```
x-api-key: your_camb_api_key
```
### Example Request
```bash cURL theme={null}
curl -X POST "https://client.camb.ai/apis/tts-stream" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello world!",
"voice_id": 147320
}'
```
```python Python theme={null}
import requests
headers = {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
response = requests.post(
"https://client.camb.ai/apis/tts-stream",
headers=headers,
json={"text": "Hello world!", "voice_id": 147320}
)
```
```typescript TypeScript theme={null}
const response = await fetch("https://client.camb.ai/apis/tts-stream", {
method: "POST",
headers: {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
text: "Hello world!",
voice_id: 147320
})
});
```
## SDK Authentication
When using the official SDKs, pass your API key during client initialization.
```python Python SDK theme={null}
from camb.client import CambAI
client = CambAI(api_key="your_api_key")
# Or use environment variable
client = CambAI(api_key=os.getenv("CAMB_API_KEY"))
```
```typescript TypeScript SDK theme={null}
import { CambClient } from '@camb-ai/sdk';
const client = new CambClient({ apiKey: "YOUR_API_KEY" });
// Or use environment variable
const client = new CambClient({ apiKey: process.env.CAMB_API_KEY });
```
## Error Responses
| Status Code | Meaning |
| ----------- | ------------------------------------------------- |
| `401` | Invalid or missing API key |
| `403` | API key doesn't have permission for this resource |
| `429` | Rate limit exceeded |
### Example Error Response
```json theme={null}
{
"error": "Invalid API key",
"status": 401
}
```
## Best Practices
Use environment variables or secure secret management systems.
Generate new API keys regularly and revoke old ones.
Create different API keys for development, staging, and production.
Check your API usage in CAMB.AI Studio to detect unauthorized access.
## Next Steps
Make your first API call
Use our official SDKs
# Baseten
Source: https://docs.camb.ai/hosting-platforms/baseten
Use Camb.ai MARS models with your own Baseten deployment
## Overview
The Camb.ai SDK supports using **Baseten** as a TTS provider, allowing you to run MARS models on your own Baseten infrastructure for enhanced control and scalability.
Deployment Link: [https://app.baseten.co/deploy/mars8-flash](https://app.baseten.co/deploy/mars8-flash)
### Key Features
* **Self-hosted Infrastructure**: Run MARS models on your own Baseten deployment
* **Voice Cloning**: Requires reference audio for voice cloning capabilities
* **Streaming Support**: Real-time audio streaming
* **Full SDK Integration**: Works seamlessly with both Python and TypeScript SDKs
***
## Prerequisites
* A Baseten account with MARS model deployed
* Your Baseten API key
* Your Baseten model URL (mars\_pro\_url)
* A reference audio file for voice cloning
***
## Installation
```bash Python theme={null}
pip install camb-sdk
```
```bash TypeScript theme={null}
npm install @camb-ai/sdk
```
## Usage
```python Python theme={null}
import base64
from camb.client import CambAI, save_stream_to_file
client = CambAI(
tts_provider="baseten",
provider_params={
"api_key": "YOUR_BASETEN_API_KEY",
"mars_pro_url": "https://model-xxxxxx.api.baseten.co/environments/production/predict"
}
)
def main():
response = client.text_to_speech.tts(
text="Hello World and my dear friends",
language="en-us",
speech_model="mars-pro",
request_options={
"additional_body_parameters": {
"reference_audio": base64.b64encode(open("audio.wav", "rb").read()).decode('utf-8'),
"reference_language": "en-us" # required
},
"timeout_in_seconds": 300
}
)
save_stream_to_file(response, "tts_output.mp3")
print("Success! Audio saved to tts_output.mp3")
if __name__ == "__main__":
main()
```
```javascript TypeScript theme={null}
import { CambClient, saveStreamToFile } from '@camb-ai/sdk';
import * as fs from 'fs';
// Initialize client with Baseten provider
const client = new CambClient({
ttsProvider: 'baseten',
providerParams: {
api_key: process.env.BASETEN_API_KEY || 'YOUR_BASETEN_API_KEY',
mars_pro_url: process.env.BASETEN_URL || 'YOUR_BASETEN_MARS_PRO_URL'
}
});
async function main() {
try {
// Read reference audio file (you need to provide this)
const referenceAudioPath = process.env.REFERENCE_AUDIO_PATH || 'reference.wav';
if (!fs.existsSync(referenceAudioPath)) {
console.error(`Reference audio file not found: ${referenceAudioPath}`);
console.log('Please provide a reference audio file or set REFERENCE_AUDIO_PATH environment variable');
return;
}
const referenceAudio = fs.readFileSync(referenceAudioPath).toString('base64');
console.log('Generating speech with Baseten provider...');
const response = await client.textToSpeech.tts({
text: 'Hello World and my dear friends',
language: 'en-us',
speech_model: 'mars-pro',
output_configuration: {
format: 'wav'
},
additional_body_parameters: {
reference_audio: referenceAudio,
reference_language: 'en-us' // required
}
});
const outputFile = 'baseten_output.wav';
await saveStreamToFile(response, outputFile);
console.log(`✓ Audio generated with Baseten provider and saved to ${outputFile}`);
} catch (error) {
console.error('Error:', error.message);
if (error.body) {
console.error('Details:', error.body);
}
}
}
main();
```
***
## Configuration
### Required Parameters
| Parameter | Description |
| -------------------- | ---------------------------------------------------- |
| `api_key` | Your Baseten API key |
| `mars_pro_url` | Your Baseten MARS model endpoint URL |
| `reference_audio` | Base64-encoded reference audio for voice cloning |
| `reference_language` | Language code of the reference audio (e.g., `en-us`) |
### Optional Parameters
| Parameter | Description | Default |
| -------------------- | ----------------------------- | ---------- |
| `speech_model` | MARS model variant | `mars-pro` |
| `language` | Target language for synthesis | `en-us` |
| `output_format` | Audio output format | `mp3` |
| `timeout_in_seconds` | Request timeout | - |
***
## Resources
* [Baseten Documentation](https://docs.baseten.co)
* [Camb.ai Python SDK](https://github.com/camb-ai/cambai-python-sdk)
* [Camb.ai TypeScript SDK](https://github.com/camb-ai/cambai-node-sdk)
# LiveKit
Source: https://docs.camb.ai/integrations/livekit
Build real-time voice AI agents with Camb.ai TTS and LiveKit Agents
Integration with LiveKit is currently being reviewed
## Overview
The **livekit-plugins-camb** package enables you to integrate Camb.ai's MARS text-to-speech models into your LiveKit voice agents. This integration provides high-quality, low-latency voice synthesis for real-time conversational AI applications.
### Key Features
* **MARS Models**: Access to Camb.ai's latest generation TTS models (mars-flash, mars-pro)
* **Multilingual**: Up to 312 languages depending on the MARS model — see [Language Support](/language-support)
* **Real-time Streaming**: HTTP chunked streaming for low-latency audio
* **Voice Customization**: Voice selection and enhanced pronunciation for names/places
* **Model-specific Sample Rates**: 22.05kHz (mars-flash) or 48kHz (mars-pro)
***
## Installation
### Prerequisites
* Python 3.9 or higher
* A Camb.ai API key ([get one here](https://studio.camb.ai))
* LiveKit Cloud account or self-hosted LiveKit server
### Install the Plugin
```bash theme={null}
pip install livekit-plugins-camb
```
For a complete voice agent setup with VAD (Voice Activity Detection):
```bash theme={null}
pip install livekit-plugins-camb 'livekit-agents[silero]' python-dotenv
```
***
## Quick Start
### 1. Set Up Environment Variables
Create a `.env` file in your project directory:
```bash theme={null}
# Camb.ai API key
CAMB_API_KEY=your_camb_api_key
# LiveKit credentials
LIVEKIT_URL=wss://your-project.livekit.cloud
LIVEKIT_API_KEY=your_livekit_api_key
LIVEKIT_API_SECRET=your_livekit_api_secret
# LLM provider (e.g., OpenAI)
OPENAI_API_KEY=your_openai_api_key
# STT provider (e.g., Deepgram)
DEEPGRAM_API_KEY=your_deepgram_api_key
```
### 2. Create Your Voice Agent
```python theme={null}
import logging
from dotenv import load_dotenv
from livekit.agents import (
Agent,
AgentServer,
AgentSession,
JobContext,
JobProcess,
cli,
room_io,
)
from livekit.plugins import camb, silero
load_dotenv()
logger = logging.getLogger("voice-agent")
class MyAgent(Agent):
def __init__(self) -> None:
super().__init__(
instructions=(
"You are a helpful voice assistant. "
"Keep your responses concise and conversational. "
"Do not use emojis or special formatting."
),
)
async def on_enter(self):
# Generate initial greeting
self.session.generate_reply(allow_interruptions=False)
server = AgentServer()
def prewarm(proc: JobProcess):
# Pre-load VAD model for faster startup
proc.userdata["vad"] = silero.VAD.load()
server.setup_fnc = prewarm
@server.rtc_session()
async def entrypoint(ctx: JobContext):
session = AgentSession(
# Speech-to-text
stt="deepgram/nova-3",
# Language model
llm="openai/gpt-4.1-mini",
# Camb.ai TTS
tts=camb.TTS(),
# Voice activity detection
vad=ctx.proc.userdata["vad"],
)
await session.start(
agent=MyAgent(),
room=ctx.room,
)
if __name__ == "__main__":
cli.run_app(server)
```
### 3. Run Your Agent
**Development mode** (with LiveKit Agents Playground):
```bash theme={null}
python your_agent.py dev
```
**Production mode**:
```bash theme={null}
python your_agent.py start
```
***
## Configuration
### TTS Options
The `camb.TTS` class accepts the following parameters:
| Parameter | Type | Default | Description |
| ------------------------ | ------ | ---------------------- | ------------------------------------------------------------- |
| `api_key` | `str` | `CAMB_API_KEY` env var | Your Camb.ai API key |
| `voice_id` | `int` | `147320` | Voice ID (use `list_voices()` to discover) |
| `language` | `str` | `"en-us"` | BCP-47 language code |
| `model` | `str` | `"mars-flash"` | MARS model to use (`mars-flash` or `mars-pro`) |
| `output_format` | `str` | `"pcm_s16le"` | Audio format |
| `enhance_named_entities` | `bool` | `False` | Enhanced pronunciation for names and places |
| `sample_rate` | `int` | Auto-detected | Audio sample rate (auto-detected from model if not specified) |
### Available Models
```python theme={null}
tts=camb.TTS(model="mars-flash")
```
Best for real-time voice agents. Lowest latency (22.05kHz) with high quality.
```python theme={null}
tts=camb.TTS(model="mars-pro")
```
Higher quality synthesis at 48kHz sample rate.
### Language Support
Camb.ai supports up to 312 languages depending on the MARS model — see [Language Support](/language-support) for the full per-model locale list. Specify the language using BCP-47 codes:
```python theme={null}
# English (US)
tts=camb.TTS(language="en-us")
# French
tts=camb.TTS(language="fr-fr")
# Spanish
tts=camb.TTS(language="es-es")
# German
tts=camb.TTS(language="de-de")
# Japanese
tts=camb.TTS(language="ja-jp")
```
***
## Advanced Usage
### Dynamic Option Updates
Update TTS settings during a session:
```python theme={null}
# Change voice mid-conversation
session.tts.update_options(voice_id=1234)
# Switch model
session.tts.update_options(model="mars-pro")
# Switch language
session.tts.update_options(language="es-es")
```
### Function Tools
Add custom capabilities to your agent using the `@function_tool` decorator. The LLM automatically discovers these functions and calls them based on user conversation.
```python theme={null}
from livekit.agents.llm import function_tool
from livekit.agents import RunContext
class MyAgent(Agent):
def __init__(self) -> None:
super().__init__(
instructions="You are a helpful assistant that can look up weather.",
)
@function_tool
async def lookup_weather(
self,
context: RunContext,
location: str,
latitude: str,
longitude: str
):
"""Called when the user asks for weather related information.
Ensure the user's location (city or region) is provided.
When given a location, please estimate the latitude and longitude of the location and
do not ask the user for them.
Args:
location: The location they are asking for
latitude: The latitude of the location, do not ask user for it
longitude: The longitude of the location, do not ask user for it
"""
# Your weather lookup logic here
return "sunny with a temperature of 70 degrees."
```
For more details, see the [LiveKit Function Tools documentation](https://docs.livekit.io/agents/logic/tools/).
### Custom HTTP Session
For advanced use cases, provide your own aiohttp session:
```python theme={null}
import aiohttp
async with aiohttp.ClientSession() as session:
tts = camb.TTS(http_session=session)
# Use TTS...
```
### Metrics and Logging
Track usage and performance:
```python theme={null}
from livekit.agents import metrics, MetricsCollectedEvent
usage_collector = metrics.UsageCollector()
@session.on("metrics_collected")
def on_metrics(ev: MetricsCollectedEvent):
metrics.log_metrics(ev.metrics)
usage_collector.collect(ev.metrics)
# Get usage summary after session
summary = usage_collector.get_summary()
logger.info(f"Session usage: {summary}")
```
***
## Full Voice Agent Example
Here's a full example combining all features.
### Installation
```bash theme={null}
pip install livekit-plugins-camb 'livekit-agents[silero]' python-dotenv
```
### Code
```python theme={null}
import logging
from dotenv import load_dotenv
from livekit.agents import (
Agent,
AgentServer,
AgentSession,
JobContext,
JobProcess,
MetricsCollectedEvent,
RunContext,
cli,
metrics,
room_io,
)
from livekit.agents.llm import function_tool
from livekit.plugins import camb, silero
from livekit.plugins.turn_detector.multilingual import MultilingualModel
logger = logging.getLogger("basic-agent")
load_dotenv()
class MyAgent(Agent):
def __init__(self) -> None:
super().__init__(
instructions="Your name is Kelly. You would interact with users via voice."
"with that in mind keep your responses concise and to the point."
"do not use emojis, asterisks, markdown, or other special characters in your responses."
"You are curious and friendly, and have a sense of humor."
"you will speak english to the user",
)
async def on_enter(self):
# when the agent is added to the session, it'll generate a reply
# according to its instructions
# Keep it uninterruptible so the client has time to calibrate AEC
self.session.generate_reply(allow_interruptions=False)
@function_tool
async def lookup_weather(
self, context: RunContext, location: str, latitude: str, longitude: str
):
"""Called when the user asks for weather related information.
Ensure the user's location (city or region) is provided.
When given a location, please estimate the latitude and longitude of the location and
do not ask the user for them.
Args:
location: The location they are asking for
latitude: The latitude of the location, do not ask user for it
longitude: The longitude of the location, do not ask user for it
"""
logger.info(f"Looking up weather for {location}")
return "sunny with a temperature of 70 degrees."
server = AgentServer()
def prewarm(proc: JobProcess):
proc.userdata["vad"] = silero.VAD.load()
server.setup_fnc = prewarm
@server.rtc_session()
async def entrypoint(ctx: JobContext):
ctx.log_context_fields = {"room": ctx.room.name}
session = AgentSession(
stt="deepgram/nova-3",
llm="openai/gpt-4.1-mini",
tts=camb.TTS(),
turn_detection=MultilingualModel(),
vad=ctx.proc.userdata["vad"],
preemptive_generation=True,
resume_false_interruption=True,
false_interruption_timeout=1.0,
)
usage_collector = metrics.UsageCollector()
@session.on("metrics_collected")
def _on_metrics_collected(ev: MetricsCollectedEvent):
metrics.log_metrics(ev.metrics)
usage_collector.collect(ev.metrics)
async def log_usage():
summary = usage_collector.get_summary()
logger.info(f"Usage: {summary}")
ctx.add_shutdown_callback(log_usage)
await session.start(
agent=MyAgent(),
room=ctx.room,
room_options=room_io.RoomOptions(
audio_input=room_io.AudioInputOptions(),
),
)
if __name__ == "__main__":
cli.run_app(server)
```
### Run
**Development mode** (opens playground in browser):
```bash theme={null}
python your_agent.py dev
```
**Production mode:**
```bash theme={null}
python your_agent.py start
```
Then connect via the [LiveKit Agents Playground](https://agents-playground.livekit.io/).
***
## Troubleshooting
### Common Issues
Ensure your `CAMB_API_KEY` environment variable is set correctly:
```bash theme={null}
export CAMB_API_KEY=your_api_key_here
```
Or pass it directly:
```python theme={null}
tts=camb.TTS(api_key="your_api_key")
```
The voice ID must be an integer. Use `list_voices()` to find available voices:
```python theme={null}
voices = await camb.list_voices()
print(voices)
```
TTS synthesis can take time for longer texts. The plugin automatically uses a minimum 60-second timeout.
For very long texts, consider breaking them into smaller chunks.
* Use `mars-pro` for highest quality (48kHz) or `mars-flash` for best latency (22.05kHz)
* Ensure your network connection is stable
* Use `pcm_s16le` format for lowest latency
Check that you can reach the Camb.ai API:
```bash theme={null}
curl -H "x-api-key: YOUR_KEY" https://client.camb.ai/apis/list-voices
```
### Debug Logging
Enable debug logging for detailed information:
```python theme={null}
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("livekit.plugins.camb")
logger.setLevel(logging.DEBUG)
```
***
## Resources
* [LiveKit Agents Documentation](https://docs.livekit.io/agents/)
* [LiveKit Agents Playground](https://agents-playground.livekit.io/)
* [Camb.ai API Reference](/api-reference/endpoint/create-tts)
* [LiveKit Agents GitHub Repository](https://github.com/livekit/agents)
* [LiveKit Slack Community](https://livekit.io/join-slack)
# Pipecat
Source: https://docs.camb.ai/integrations/pipecat
Build real-time voice AI agents with Camb.ai TTS and Pipecat
## Overview
The **pipecat-ai** framework provides a `CambTTSService` that integrates Camb.ai's MARS text-to-speech models into your voice AI pipelines. This integration enables high-quality, low-latency voice synthesis for real-time conversational AI applications.
### Key Features
* **MARS Models**: Access to Camb.ai's latest generation TTS models (mars-flash, mars-pro)
* **140+ Languages**: Extensive multilingual support
* **Real-time Streaming**: Streaming audio chunks for low-latency output
* **Model-specific Sample Rates**: 22.05kHz (mars-flash) or 48kHz (mars-pro)
* **Multiple Transports**: Works with Daily, Twilio, WebRTC, and WebSocket transports
***
## Installation
### Prerequisites
* Python 3.9 or higher
* A Camb.ai API key ([get one here](https://studio.camb.ai))
* A transport provider account (e.g., Daily, Twilio)
### Install Pipecat with Camb.ai Support
```bash theme={null}
pip install "pipecat-ai[camb,silero]"
```
For a complete voice agent setup with specific transports:
```bash theme={null}
# With Daily transport
pip install "pipecat-ai[camb,silero,daily]"
# With Twilio transport
pip install "pipecat-ai[camb,silero,websocket]"
```
***
## Quick Start
### 1. Set Up Environment Variables
Create a room at [Daily Dashboard](https://dashboard.daily.co/rooms), then create a `.env` file in your project directory:
```bash theme={null}
# Camb.ai API key
CAMB_API_KEY=your_camb_api_key
# Daily room configuration
DAILY_ROOM_URL=https://your-domain.daily.co/room-name
DAILY_TOKEN=your_daily_token # Optional for public rooms
# STT provider (e.g., Deepgram)
DEEPGRAM_API_KEY=your_deepgram_api_key
# LLM provider (e.g., OpenAI)
OPENAI_API_KEY=your_openai_api_key
```
### 2. Create Your Voice Agent
```python theme={null}
import asyncio
import os
from dotenv import load_dotenv
from loguru import logger
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams
from pipecat.frames.frames import LLMRunFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair
from pipecat.services.camb.tts import CambTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.daily.transport import DailyTransport, DailyParams
load_dotenv()
async def main():
# Get room configuration from environment
room_url = os.getenv("DAILY_ROOM_URL")
token = os.getenv("DAILY_TOKEN", "") # Don't include this for public rooms
# to generate a token, you can use this curl command:
# curl -H "Content-Type: application/json" \
# -H "Authorization: Bearer " \
# -XPOST -d '{"properties":{"room_name":""}}' \
# https://api.daily.co/v1/meeting-tokens
# then use the token in the DAILY_TOKEN environment variable
# then join the room with the token. https://your-room-url.daily.co/room-id?t=your-room-token
if not room_url:
raise ValueError("DAILY_ROOM_URL environment variable is required")
logger.info(f"Connecting to room: {room_url}")
# Configure transport
transport = DailyTransport(
room_url=room_url,
token=token,
bot_name="Camb Voice Bot",
params=DailyParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
),
)
# Initialize services
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CambTTSService(
api_key=os.getenv("CAMB_API_KEY"),
model="mars-flash",
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"))
# Set up conversation context
messages = [
{
"role": "system",
"content": "You are a helpful voice assistant. "
"Keep your responses concise and conversational. "
"Avoid special characters or emojis.",
},
]
context = LLMContext(messages)
context_aggregator = LLMContextAggregatorPair(context)
# Build the pipeline
pipeline = Pipeline(
[
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
]
)
task = PipelineTask(
pipeline,
params=PipelineParams(
enable_metrics=True,
enable_usage_metrics=True,
),
)
# Handle client connection
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info("Client connected")
messages.append({"role": "system", "content": "Please introduce yourself briefly."})
await task.queue_frames([LLMRunFrame()])
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info("Client disconnected")
await task.cancel()
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__":
asyncio.run(main())
```
### 3. Run Your Agent
```bash theme={null}
python your_agent.py
```
***
## Configuration
### CambTTSService Options
The `CambTTSService` class accepts the following parameters:
| Parameter | Type | Default | Description |
| ------------- | ------------- | -------------- | -------------------------------------------------------------------- |
| `api_key` | `str` | Required | Your Camb.ai API key |
| `voice_id` | `int` | `147320` | Voice ID (browse voices at [Camb.ai Studio](https://studio.camb.ai)) |
| `model` | `str` | `"mars-flash"` | MARS model to use |
| `timeout` | `float` | `60.0` | Request timeout in seconds |
| `sample_rate` | `int` | Auto | Audio sample rate (auto-detected from model) |
| `params` | `InputParams` | `None` | Additional voice parameters |
### InputParams Options
| Parameter | Type | Default | Description |
| ---------- | ---------- | ------------- | ---------------------- |
| `language` | `Language` | `Language.EN` | Language for synthesis |
### Available Models
```python theme={null}
tts = CambTTSService(
api_key=os.getenv("CAMB_API_KEY"),
model="mars-flash",
)
```
Best for real-time voice agents. Lowest latency at 22.05kHz sample rate.
```python theme={null}
tts = CambTTSService(
api_key=os.getenv("CAMB_API_KEY"),
model="mars-pro",
)
```
Highest quality output at 48kHz sample rate.
### Language Support
Camb.ai supports up to 312 languages depending on the MARS model — see [Language Support](/language-support) for the full per-model locale list. Specify the language using Pipecat's `Language` enum:
```python theme={null}
from pipecat.transcriptions.language import Language
from pipecat.services.camb.tts import CambTTSService
# English (US)
tts = CambTTSService(
api_key=os.getenv("CAMB_API_KEY"),
params=CambTTSService.InputParams(language=Language.EN_US),
)
# French
tts = CambTTSService(
api_key=os.getenv("CAMB_API_KEY"),
params=CambTTSService.InputParams(language=Language.FR),
)
# Spanish
tts = CambTTSService(
api_key=os.getenv("CAMB_API_KEY"),
params=CambTTSService.InputParams(language=Language.ES),
)
# Japanese
tts = CambTTSService(
api_key=os.getenv("CAMB_API_KEY"),
params=CambTTSService.InputParams(language=Language.JA),
)
```
***
## Advanced Usage
### Dynamic Settings Updates
Update TTS settings during runtime:
```python theme={null}
# Update language
await tts._update_settings({"language": Language.ES})
# Update voice
await tts._update_settings({"voice_id": 12345})
```
### Using with Multiple Transports
Pipecat supports multiple transport backends. Here's how to configure Camb.ai TTS with different transports:
```python theme={null}
from pipecat.transports.daily.transport import DailyTransport, DailyParams
from pipecat.transports.websocket.fastapi import FastAPIWebsocketTransport, FastAPIWebsocketParams
from pipecat.transports.webrtc.transport import WebRTCTransport, TransportParams
# Daily transport
daily_transport = DailyTransport(
room_url="...",
token="...",
params=DailyParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
# WebSocket transport (for Twilio)
websocket_transport = FastAPIWebsocketTransport(
params=FastAPIWebsocketParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
),
)
```
### Metrics and Logging
Track usage and performance with Pipecat's built-in metrics:
```python theme={null}
from pipecat.pipeline.task import PipelineParams, PipelineTask
task = PipelineTask(
pipeline,
params=PipelineParams(
enable_metrics=True,
enable_usage_metrics=True,
),
)
```
Enable debug logging for detailed information:
```python theme={null}
from loguru import logger
logger.enable("pipecat")
```
***
## Multi-Transport Voice Agent
Here's a full example using the Pipecat runner utilities for transport-agnostic deployment:
```python theme={null}
import os
from dotenv import load_dotenv
from loguru import logger
from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams
from pipecat.frames.frames import LLMRunFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import (
LLMContextAggregatorPair,
LLMUserAggregatorParams,
)
from pipecat.runner.types import RunnerArguments
from pipecat.runner.utils import create_transport
from pipecat.services.camb.tts import CambTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.base_transport import BaseTransport, TransportParams
from pipecat.transports.daily.transport import DailyParams
from pipecat.transports.websocket.fastapi import FastAPIWebsocketParams
from pipecat.turns.user_stop import TurnAnalyzerUserTurnStopStrategy
from pipecat.turns.user_turn_strategies import UserTurnStrategies
load_dotenv(override=True)
transport_params = {
"daily": lambda: DailyParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
),
"twilio": lambda: FastAPIWebsocketParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
),
"webrtc": lambda: TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
),
}
async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
logger.info("Starting Camb.ai TTS bot")
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CambTTSService(
api_key=os.getenv("CAMB_API_KEY"),
model="mars-flash",
)
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"))
messages = [
{
"role": "system",
"content": "You are a helpful voice assistant powered by Camb.ai. "
"Keep your responses concise and conversational. "
"Avoid special characters, emojis, or bullet points.",
},
]
context = LLMContext(messages)
user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
context,
user_params=LLMUserAggregatorParams(
user_turn_strategies=UserTurnStrategies(
stop=[TurnAnalyzerUserTurnStopStrategy(turn_analyzer=LocalSmartTurnAnalyzerV3())]
),
),
)
pipeline = Pipeline(
[
transport.input(),
stt,
user_aggregator,
llm,
tts,
transport.output(),
assistant_aggregator,
]
)
task = PipelineTask(
pipeline,
params=PipelineParams(
enable_metrics=True,
enable_usage_metrics=True,
audio_out_sample_rate=22050,
),
idle_timeout_secs=runner_args.pipeline_idle_timeout_secs,
)
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
logger.info("Client connected")
messages.append({"role": "system", "content": "Please introduce yourself."})
await task.queue_frames([LLMRunFrame()])
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
logger.info("Client disconnected")
await task.cancel()
runner = PipelineRunner(handle_sigint=runner_args.handle_sigint)
await runner.run(task)
async def bot(runner_args: RunnerArguments):
"""Main bot entry point compatible with Pipecat Cloud."""
transport = await create_transport(runner_args, transport_params)
await run_bot(transport, runner_args)
if __name__ == "__main__":
from pipecat.runner.run import main
main()
```
***
## Tutorial: Local Voice Agent
Build a voice agent that runs on your local machine using your microphone and speakers - perfect for quick prototyping.
### Installation
```bash theme={null}
pip install "pipecat-ai[camb,silero,local]"
```
### Local Audio Example
```python theme={null}
import asyncio
import os
from dotenv import load_dotenv
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams
from pipecat.frames.frames import LLMRunFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair
from pipecat.services.camb.tts import CambTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.local.audio import LocalAudioTransport, LocalAudioTransportParams
load_dotenv()
async def main():
transport = LocalAudioTransport(
LocalAudioTransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
)
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CambTTSService(api_key=os.getenv("CAMB_API_KEY"), model="mars-flash")
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"))
messages = [{"role": "system", "content": "You are a helpful voice assistant."}]
context = LLMContext(messages)
context_aggregator = LLMContextAggregatorPair(context)
pipeline = Pipeline([
transport.input(),
stt,
context_aggregator.user(),
llm,
tts,
transport.output(),
context_aggregator.assistant(),
])
task = PipelineTask(pipeline, params=PipelineParams(audio_out_sample_rate=22050))
@task.event_handler("on_pipeline_started")
async def on_started(task, frame):
messages.append({"role": "system", "content": "Please introduce yourself."})
await task.queue_frames([LLMRunFrame()])
runner = PipelineRunner()
await runner.run(task)
if __name__ == "__main__":
asyncio.run(main())
```
***
## Tutorial: Self-Hosted WebRTC Agent
Deploy a voice agent accessible from any browser without third-party services.
### Installation
```bash theme={null}
pip install "pipecat-ai[camb,silero,webrtc]" pipecat-ai-small-webrtc-prebuilt fastapi uvicorn
```
### WebRTC Server Example
```python theme={null}
import os
import uuid
from typing import Dict
import uvicorn
from dotenv import load_dotenv
from fastapi import BackgroundTasks, FastAPI, Request
from fastapi.responses import RedirectResponse
from pipecat_ai_small_webrtc_prebuilt.frontend import SmallWebRTCPrebuiltUI
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.audio.vad.vad_analyzer import VADParams
from pipecat.frames.frames import LLMRunFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair
from pipecat.services.camb.tts import CambTTSService
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.services.openai.llm import OpenAILLMService
from pipecat.transports.base_transport import TransportParams
from pipecat.transports.smallwebrtc.connection import IceServer, SmallWebRTCConnection
from pipecat.transports.smallwebrtc.transport import SmallWebRTCTransport
load_dotenv()
app = FastAPI()
connections: Dict[str, SmallWebRTCConnection] = {}
sessions: Dict[str, Dict] = {}
ice_servers = [IceServer(urls="stun:stun.l.google.com:19302")]
app.mount("/client", SmallWebRTCPrebuiltUI)
async def run_bot(conn: SmallWebRTCConnection):
transport = SmallWebRTCTransport(
webrtc_connection=conn,
params=TransportParams(
audio_in_enabled=True,
audio_out_enabled=True,
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
),
)
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
tts = CambTTSService(api_key=os.getenv("CAMB_API_KEY"), model="mars-flash")
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"))
messages = [{"role": "system", "content": "You are a helpful voice assistant."}]
context = LLMContext(messages)
context_aggregator = LLMContextAggregatorPair(context)
pipeline = Pipeline([
transport.input(), stt, context_aggregator.user(),
llm, tts, transport.output(), context_aggregator.assistant(),
])
task = PipelineTask(pipeline, params=PipelineParams(enable_metrics=True))
@transport.event_handler("on_client_connected")
async def on_connected(transport, client):
messages.append({"role": "system", "content": "Please introduce yourself."})
await task.queue_frames([LLMRunFrame()])
@transport.event_handler("on_client_disconnected")
async def on_disconnected(transport, client):
await task.cancel()
runner = PipelineRunner(handle_sigint=False)
await runner.run(task)
@app.get("/")
async def root():
return RedirectResponse(url="/client/")
@app.post("/start")
async def start(request: Request):
"""RTVI protocol: Create a new session."""
try:
request_data = await request.json()
except Exception:
request_data = {}
session_id = str(uuid.uuid4())
sessions[session_id] = request_data
result = {"sessionId": session_id}
if request_data.get("enableDefaultIceServers"):
result["iceConfig"] = {"iceServers": [{"urls": "stun:stun.l.google.com:19302"}]}
return result
@app.api_route("/sessions/{session_id}/{path:path}", methods=["POST", "PATCH"])
async def session_proxy(session_id: str, path: str, request: Request, background_tasks: BackgroundTasks):
"""RTVI protocol: Proxy requests to session endpoints."""
if session_id not in sessions:
return {"error": "Invalid session"}, 404
if path.endswith("api/offer"):
request_data = await request.json()
return await offer(request_data, background_tasks)
return {"status": "ok"}
@app.post("/api/offer")
async def offer(request: dict, background_tasks: BackgroundTasks):
pc_id = request.get("pc_id")
if pc_id and pc_id in connections:
conn = connections[pc_id]
await conn.renegotiate(
sdp=request["sdp"],
type=request["type"],
restart_pc=request.get("restart_pc", False),
)
else:
conn = SmallWebRTCConnection(ice_servers)
await conn.initialize(sdp=request["sdp"], type=request["type"])
@conn.event_handler("closed")
async def handle_closed(c: SmallWebRTCConnection):
connections.pop(c.pc_id, None)
background_tasks.add_task(run_bot, conn)
answer = conn.get_answer()
connections[answer["pc_id"]] = conn
return answer
if __name__ == "__main__":
uvicorn.run(app, host="localhost", port=7860)
```
Run and open [http://localhost:7860](http://localhost:7860) in your browser.
***
## Troubleshooting
### Common Issues
Ensure your `CAMB_API_KEY` environment variable is set correctly:
```bash theme={null}
export CAMB_API_KEY=your_api_key_here
```
Or pass it directly:
```python theme={null}
tts = CambTTSService(api_key="your_api_key")
```
The voice ID must be an integer. Browse available voices at [Camb.ai Studio](https://studio.camb.ai) to find valid voice IDs.
Camb.ai requires a minimum of 3 characters for TTS synthesis. The service will log a warning and skip synthesis for shorter text.
TTS synthesis can take time for longer texts. The default timeout is 60 seconds. For very long texts, consider:
* Breaking them into smaller chunks
* Increasing the timeout: `CambTTSService(..., timeout=120.0)`
Different models use different sample rates:
* `mars-flash`: 22.05kHz
* `mars-pro`: 48kHz
The service automatically selects the correct sample rate based on the model. If you need a specific rate, pass it explicitly:
```python theme={null}
tts = CambTTSService(..., sample_rate=48000)
```
### Debug Logging
Enable debug logging for detailed information:
```python theme={null}
from loguru import logger
# Enable all pipecat logging
logger.enable("pipecat")
# Or enable specific module logging
import logging
logging.basicConfig(level=logging.DEBUG)
```
***
## Resources
* [Pipecat Documentation](https://docs.pipecat.ai/)
* [Pipecat GitHub Repository](https://github.com/pipecat-ai/pipecat)
* [Camb.ai API Reference](/api-reference/endpoint/create-tts)
* [Pipecat Examples](https://github.com/pipecat-ai/pipecat/tree/main/examples)
* [Pipecat Discord Community](https://discord.gg/pipecat)
# Introduction
Source: https://docs.camb.ai/introduction
CAMB.AI is the localization AI infrastructure company built to help the world’s biggest Enterprises reach 8 billion fans, customers and viewers. Supporting 140+ languages!
Explore our docs to integrate Camb AI's MARS & BOLI models into your applications.
Learn how to install and use the Python & Node.js SDKs to build voice apps quickly.
Access MARS models on your own favorite cloud providers like Google Cloud, Modal, Baseten, etc.
Explore our open-source models MARS 6 and MARS 5 on GitHub.
## Quick Start
***
## Features Suite
* **Live Streaming**: Deliver live content globally with real-time audio translation and dubbing.
* **Live Text to Speech**: Realistic, emotional speech synthesis, featuring MARS 8 in 4 variants - mars pro, mars flash, mars instruct, and mars nano. Available on all cloud providers.
* **Translation**: Context-aware neural translation using our proprietary BOLI Model.
* **Dubbing**: Automated video dubbing using our AI that preserves emotional delivery across 140+ languages.
* **Voice Cloning**: Create digital voice replicas from audio as short as 2 seconds.
* **Audio Separation**: Isolate and extract distinct audio components from mixed recordings using deep learning to separate speech from background elements.
* **Sound and Music**: Create high-quality music and realistic soundscapes, delivering immersive audio experiences from simple text prompts.
* **Transcription**: Convert speech to text with speaker identification, timestamps, and specialized terminology (dictionaries) support.
* **Subtitles**: Generate subtitle-ready cues from a media file, translated into any number of target languages in one call.
and more!
Continue exploring our detailed documentation for each API:
Stream real-time dubbed content for live events, broadcasts, and interactive applications.
Transform text into natural-sounding speech with customizable voice features across 140+ languages
Translate text and synthesize speech in one step across 140+ languages
Localize your content using our AI that preserves emotional delivery across 140+ languages
Convert written narratives into audiobooks using your own voice or custom voice.
Translate and convert narratives into audiobooks in 140+ languages
Translate content across 140+ language pairs with context-aware neural technology.
Convert speech to text with speaker identification, timestamps, and specialized terminology (dictionaries) support.
Generate subtitle-ready cues from a media file, translated into any number of target languages in one call.
Create unique voices by describing characteristics or clone existing voices from audio samples for consistent brand identity.
Create high-quality music and realistic soundscapes, delivering immersive audio experiences from simple text prompts.
Isolate and extract distinct audio components from mixed recordings using deep learning to separate speech from background elements.
# Language Support
Source: https://docs.camb.ai/language-support
Each MARS model supports a different set of languages and locales. Use the locale code (e.g. `en-us`) as the `language` parameter when calling the API.
## MARS-Flash & MARS-Pro (MARS 8)
Supported in `mars-flash` and `mars-pro`. **33 languages supported.**
| Code | Language |
| :------ | :-------------------- |
| `en-us` | English (USA) |
| `en-in` | English (India) |
| `zh-cn` | Chinese (China) |
| `fr-fr` | French (France) |
| `de-de` | German (Germany) |
| `ja-jp` | Japanese (Japan) |
| `ru-ru` | Russian (Russia) |
| `ko-kr` | Korean (South Korea) |
| `es-es` | Spanish (Spain) |
| `es-mx` | Spanish (Mexico) |
| `pt-pt` | Portuguese (Portugal) |
| `pt-br` | Portuguese (Brazil) |
| `ar-sa` | Arabic (Saudi Arabia) |
| `id-id` | Indonesian (ID) |
| `hi-in` | Hindi (India) |
| `nl-nl` | Dutch (Netherlands) |
| `ar-xa` | Arabic (Pan-Arabic) |
| `ar-sy` | Arabic (Syria) |
| `it-it` | Italian (Italy) |
| `ar-eg` | Arabic (Egypt) |
| `ta-in` | Tamil (India) |
| `te-in` | Telugu (India) |
| `bn-in` | Bengali (India) |
| `ar-ma` | Arabic (Morocco) |
| `mr-in` | Marathi (India) |
| `kn-in` | Kannada (India) |
| `bn-bd` | Bengali (Bangladesh) |
| `as-in` | Assamese (India) |
| `ml-in` | Malayalam (India) |
| `fr-ca` | French (Canada) |
| `pl-pl` | Polish (Poland) |
| `tr-tr` | Turkish (Turkey) |
| `pa-in` | Punjabi (India) |
## MARS 8.1 Beta Models
Supported in `mars-8.1-flash-beta` and `mars-8.1-pro-beta`. **312 languages supported.**
| Code | Language |
| :--------------- | :---------------------------------------- |
| `en-us` | English (USA) |
| `af-za` | Afrikaans (South Africa) |
| `am-et` | Amharic (Ethiopia) |
| `ar-ae` | Arabic (UAE) |
| `ar-bh` | Arabic (Bahrain) |
| `ar-dz` | Arabic (Algeria) |
| `ar-eg` | Arabic (Egypt) |
| `ar-iq` | Arabic (Iraq) |
| `ar-jo` | Arabic (Jordan) |
| `ar-kw` | Arabic (Kuwait) |
| `ar-lb` | Arabic (Lebanon) |
| `ar-ly` | Arabic (Libya) |
| `ar-ma` | Arabic (Morocco) |
| `ar-om` | Arabic (Oman) |
| `ar-qa` | Arabic (Qatar) |
| `ar-sa` | Arabic (Saudi Arabia) |
| `ar-sy` | Arabic (Syria) |
| `ar-tn` | Arabic (Tunisia) |
| `ar-ye` | Arabic (Yemen) |
| `az-az` | Azerbaijani (Azerbaijan) |
| `bg-bg` | Bulgarian (Bulgaria) |
| `bn-bd` | Bengali (Bangladesh) |
| `bn-in` | Bengali (India) |
| `bs-ba` | Bosnian (Bosnia & Herz.) |
| `ca-es` | Catalan (Spain) |
| `cs-cz` | Czech (Czechia) |
| `cy-gb` | Welsh (United Kingdom) |
| `da-dk` | Danish (Denmark) |
| `de-at` | German (Austria) |
| `de-ch` | German (Switzerland) |
| `de-de` | German (Germany) |
| `el-gr` | Greek (Greece) |
| `en-au` | English (Australia) |
| `en-ca` | English (Canada) |
| `en-gb` | English (United Kingdom) |
| `en-hk` | English (Hong Kong) |
| `en-ie` | English (Ireland) |
| `en-in` | English (India) |
| `en-ke` | English (Kenya) |
| `en-ng` | English (Nigeria) |
| `en-nz` | English (New Zealand) |
| `en-ph` | English (Philippines) |
| `en-sg` | English (Singapore) |
| `en-tz` | English (Tanzania) |
| `en-za` | English (South Africa) |
| `es-ar` | Spanish (Argentina) |
| `es-bo` | Spanish (Bolivia) |
| `es-cl` | Spanish (Chile) |
| `es-co` | Spanish (Colombia) |
| `es-cr` | Spanish (Costa Rica) |
| `es-cu` | Spanish (Cuba) |
| `es-do` | Spanish (Dominican Rep.) |
| `es-ec` | Spanish (Ecuador) |
| `es-es` | Spanish (Spain) |
| `es-gq` | Spanish (Eq. Guinea) |
| `es-gt` | Spanish (Guatemala) |
| `es-hn` | Spanish (Honduras) |
| `es-mx` | Spanish (Mexico) |
| `es-ni` | Spanish (Nicaragua) |
| `es-pa` | Spanish (Panama) |
| `es-pe` | Spanish (Peru) |
| `es-pr` | Spanish (Puerto Rico) |
| `es-py` | Spanish (Paraguay) |
| `es-sv` | Spanish (El Salvador) |
| `es-us` | Spanish (USA) |
| `es-uy` | Spanish (Uruguay) |
| `es-ve` | Spanish (Venezuela) |
| `et-ee` | Estonian (Estonia) |
| `eu-es` | Basque (Spain) |
| `fa-ir` | Persian (Iran) |
| `fi-fi` | Finnish (Finland) |
| `fil-ph` | Filipino (Philippines) |
| `fr-be` | French (Belgium) |
| `fr-ca` | French (Canada) |
| `fr-ch` | French (Switzerland) |
| `fr-fr` | French (France) |
| `ga-ie` | Irish (Ireland) |
| `gl-es` | Galician (Spain) |
| `gu-in` | Gujarati (India) |
| `he-il` | Hebrew (Israel) |
| `hi-in` | Hindi (India) |
| `hr-hr` | Croatian (Croatia) |
| `hu-hu` | Hungarian (Hungary) |
| `hy-am` | Armenian (Armenia) |
| `id-id` | Indonesian (ID) |
| `is-is` | Icelandic (Iceland) |
| `it-it` | Italian (Italy) |
| `ja-jp` | Japanese (Japan) |
| `jv-id` | Javanese (ID) |
| `ka-ge` | Georgian (Georgia) |
| `kk-kz` | Kazakh (Kazakhstan) |
| `km-kh` | Khmer (Cambodia) |
| `kn-in` | Kannada (India) |
| `ko-kr` | Korean (South Korea) |
| `lo-la` | Lao (Laos) |
| `lt-lt` | Lithuanian (Lithuania) |
| `lv-lv` | Latvian (Latvia) |
| `mk-mk` | Macedonian (N. Macedonia) |
| `ml-in` | Malayalam (India) |
| `mn-mn` | Mongolian (Mongolia) |
| `mr-in` | Marathi (India) |
| `ms-my` | Malay (Malaysia) |
| `mt-mt` | Maltese (Malta) |
| `my-mm` | Burmese (Myanmar) |
| `nb-no` | Norwegian Bokmål (Norway) |
| `nl-be` | Dutch (Belgium) |
| `nl-nl` | Dutch (Netherlands) |
| `pl-pl` | Polish (Poland) |
| `ps-af` | Pashto (Afghanistan) |
| `pt-br` | Portuguese (Brazil) |
| `pt-pt` | Portuguese (Portugal) |
| `ro-ro` | Romanian (Romania) |
| `ru-ru` | Russian (Russia) |
| `si-lk` | Sinhala (Sri Lanka) |
| `sk-sk` | Slovak (Slovakia) |
| `sl-si` | Slovenian (Slovenia) |
| `so-so` | Somali (Somalia) |
| `sq-al` | Albanian (Albania) |
| `sr-rs` | Serbian (Serbia) |
| `sv-se` | Swedish (Sweden) |
| `sw-ke` | Swahili (Kenya) |
| `sw-tz` | Swahili (Tanzania) |
| `ta-in` | Tamil (India) |
| `ta-lk` | Tamil (Sri Lanka) |
| `ta-my` | Tamil (Malaysia) |
| `ta-sg` | Tamil (Singapore) |
| `te-in` | Telugu (India) |
| `th-th` | Thai (Thailand) |
| `tr-tr` | Turkish (Turkey) |
| `uk-ua` | Ukrainian (Ukraine) |
| `ur-in` | Urdu (India) |
| `ur-pk` | Urdu (Pakistan) |
| `uz-uz` | Uzbek (Uzbekistan) |
| `vi-vn` | Vietnamese (Vietnam) |
| `zh-cn` | Chinese (China) |
| `zh-cn-henan` | Chinese (China, Henan) |
| `zh-cn-liaoning` | Chinese (China, Liaoning) |
| `zh-cn-shaanxi` | Chinese (China, Shaanxi) |
| `zh-cn-shandong` | Chinese (China, Shandong) |
| `zh-cn-sichuan` | Chinese (China, Sichuan) |
| `zh-hk` | Chinese (Hong Kong) |
| `zh-tw` | Chinese (Taiwan) |
| `zu-za` | Zulu (South Africa) |
| `pa-in` | Punjabi (India) |
| `sa-in` | Sanskrit (India) |
| `ar-xa` | Arabic (Pan-Arabic) |
| `tl-ph` | Tagalog (Philippines) |
| `es-xl` | Spanish (Latin America) |
| `as-in` | Assamese (India) |
| `or-in` | Odia (India) |
| `mai-in` | Maithili (India) |
| `sd-in` | Sindhi (India) |
| `kok-in` | Konkani (India) |
| `mni-in` | Manipuri (India) |
| `ks-in` | Kashmiri (India) |
| `doi-in` | Dogri (India) |
| `brx-in` | Bodo (India) |
| `sat-in` | Santali (India) |
| `yue-hk` | Cantonese (Hong Kong) |
| `no-no` | Norwegian (Norway) |
| `rw-rw` | Kinyarwanda (Rwanda) |
| `be-by` | Belarusian (Belarus) |
| `eo-xx` | Esperanto (Generic) |
| `kab-dz` | Kabyle (Algeria) |
| `lg-ug` | Ganda (Uganda) |
| `ug-cn` | Uighur (China) |
| `mhr-ru` | Eastern Mari (Russia) |
| `ba-ru` | Bashkir (Russia) |
| `ars-sa` | Najdi Arabic (Saudi Arabia) |
| `npi-np` | Nepali (Nepal) |
| `ckb-iq` | Central Kurdish (Iraq) |
| `dgo-in` | Dogri (India) |
| `knn-in` | Konkani (India) |
| `kbd-ru` | Kabardian (Russia) |
| `ary-ma` | Moroccan Arabic (Morocco) |
| `afb-kw` | Gulf Arabic (Kuwait) |
| `bo-cn` | Tibetan (China) |
| `fy-nl` | Western Frisian (Netherlands) |
| `kmr-xx` | Northern Kurdish (Generic) |
| `ab-ge` | Abkhazian (Georgia) |
| `adx-cn` | Amdo Tibetan (China) |
| `ky-kg` | Kirghiz (Kyrgyzstan) |
| `kln-xx` | Kalenjin (Generic) |
| `dv-mv` | Dhivehi (Maldives) |
| `luo-xx` | Luo (Generic) |
| `ady-ru` | Adyghe (Russia) |
| `mrj-xx` | Western Mari (Generic) |
| `tt-ru` | Tatar (Russia) |
| `ltg-xx` | Latgalian (Generic) |
| `br-fr` | Breton (France) |
| `phr-xx` | Pahari-Potwari (Generic) |
| `cv-ru` | Chuvash (Russia) |
| `arz-eg` | Egyptian Arabic (Egypt) |
| `gui-bo` | Eastern Bolivian Guaraní (Bolivia) |
| `acw-sa` | Hijazi Arabic (Saudi Arabia) |
| `acx-xx` | Omani Arabic (Generic) |
| `orc-xx` | Orma (Generic) |
| `mvy-xx` | Indus Kohistani (Generic) |
| `aeb-xx` | Tunisian Arabic (Generic) |
| `gjk-xx` | Kachi Koli (Generic) |
| `phl-xx` | Phalura (Generic) |
| `odk-xx` | Od (Generic) |
| `lus-xx` | Lushai (Generic) |
| `ayl-xx` | Libyan Arabic (Generic) |
| `fue-ne` | Borgu Fulfulde (Niger) |
| `hno-xx` | Northern Hindko (Generic) |
| `kxp-xx` | Wadiyara Koli (Generic) |
| `brh-pk` | Brahui (Pakistan) |
| `plt-xx` | Plateau Malagasy (Generic) |
| `gbm-in` | Garhwali (India) |
| `bmm-xx` | Northern Betsimisaraka Malagasy (Generic) |
| `rof-xx` | Rombo (Generic) |
| `ydd-xx` | Eastern Yiddish (Generic) |
| `mi-nz` | Maori (New Zealand) |
| `ln-cd` | Lingala (DR Congo) |
| `xmv-mg` | Antankarana Malagasy (Madagascar) |
| `tkg-xx` | Tesaka Malagasy (Generic) |
| `ha-ng` | Hausa (Nigeria) |
| `nan-xx` | Min Nan Chinese (Generic) |
| `bzc-xx` | Southern Betsimisaraka Malagasy (Generic) |
| `oc-fr` | Occitan (France) |
| `oru-xx` | Ormuri (Generic) |
| `ksf-cm` | Bafia (Cameroon) |
| `an-es` | Aragonese (Spain) |
| `bft-pk` | Balti (Pakistan) |
| `nnh-xx` | Ngiemboon (Generic) |
| `sah-xx` | Yakut (Generic) |
| `pms-xx` | Piemontese (Generic) |
| `lij-xx` | Ligurian (Generic) |
| `yo-ng` | Yoruba (Nigeria) |
| `vro-xx` | Võro (Generic) |
| `apc-xx` | Levantine Arabic (Generic) |
| `khw-xx` | Khowar (Generic) |
| `uzn-xx` | Northern Uzbek (Generic) |
| `fui-cm` | Bagirmi Fulfulde (Cameroon) |
| `bnm-cm` | Batanga (Cameroon) |
| `trw-xx` | Torwali (Generic) |
| `fuc-xx` | Pulaar (Generic) |
| `kam-xx` | Kamba (Generic) |
| `msh-xx` | Masikoro Malagasy (Generic) |
| `ff-sn` | Fulah (Senegal) |
| `fuf-xx` | Pular (Generic) |
| `pwn-xx` | Paiwan (Generic) |
| `ig-xx` | Igbo (Generic) |
| `ext-es` | Extremaduran (Spain) |
| `tok-xx` | Toki Pona (Generic) |
| `ia-xx` | Interlingua (Generic) |
| `xh-za` | Xhosa (South Africa) |
| `scn-xx` | Sicilian (Generic) |
| `koo-xx` | Konzo (Generic) |
| `fub-cm` | Adamawa Fulfulde (Cameroon) |
| `plk-xx` | Kohistani Shina (Generic) |
| `ewo-cm` | Ewondo (Cameroon) |
| `nso-xx` | Pedi (Generic) |
| `gby-ng` | Gbari (Nigeria) |
| `gdf-ng` | Guduf-Gava (Nigeria) |
| `ceb-ph` | Cebuano (Philippines) |
| `gwt-af` | Gawar-Bati (Afghanistan) |
| `kw-gb` | Cornish (United Kingdom) |
| `bhr-mg` | Bara Malagasy (Madagascar) |
| `dua-cm` | Duala (Cameroon) |
| `gbr-ng` | Gbagyi (Nigeria) |
| `txy-xx` | Tanosy Malagasy (Generic) |
| `mxu-xx` | Mada (Cameroon) |
| `kna-ng` | Dera (Nigeria) |
| `kfp-xx` | Korwa (Generic) |
| `its-xx` | Isekiri (Generic) |
| `haw-us` | Hawaiian (USA) |
| `tcy-xx` | Tulu (Generic) |
| `bjn-id` | Banjar (ID) |
| `wbl-xx` | Wakhi (Generic) |
| `pbt-xx` | Southern Pashto (Generic) |
| `xmw-xx` | Tsimihety Malagasy (Generic) |
| `szy-xx` | Sakizaya (Generic) |
| `xmf-xx` | Mingrelian (Generic) |
| `twu-xx` | Termanu (Generic) |
| `nlv-xx` | Orizaba Nahuatl (Generic) |
| `qxw-xx` | Jauja Wanca Quechua (Generic) |
| `pst-af` | Central Pashto (Afghanistan) |
| `wji-xx` | Warji (Generic) |
| `fat-gh` | Fanti (Ghana) |
| `bhh-il` | Bukharic (Israel) |
| `tlp-mx` | Filomena Mata-Coahuitlán Totonac (Mexico) |
| `ldb-ng` | Dũya (Nigeria) |
| `ndi-xx` | Samba Leko (Generic) |
| `elm-ng` | Eleme (Nigeria) |
| `jns-xx` | Jaunsari (Generic) |
| `hwo-xx` | Hwana (Generic) |
| `bbl-ge` | Bats (Georgia) |
| `afo-ng` | Eloyi (Nigeria) |
| `abb-cm` | Bankon (Cameroon) |
| `jal-xx` | Yalahatan (Generic) |
| `idu-xx` | Idoma (Generic) |
| `bew-id` | Betawi (ID) |
| `qup-xx` | Southern Pastaza Quechua (Generic) |
| `noe-xx` | Nimadi (Generic) |
| `byc-xx` | Ubaghara (Generic) |
| `bug-id` | Buginese (ID) |
| `btm-id` | Batak Mandailing (ID) |
| `hia-xx` | Lamang (Generic) |
| `deg-ng` | Degema (Nigeria) |
| `kvx-xx` | Parkari Koli (Generic) |
| `pcm-xx` | Nigerian Pidgin (Generic) |
| `ijn-xx` | Kalabari (Generic) |
| `ala-ng` | Alago (Nigeria) |
| `pbu-xx` | Northern Pashto (Generic) |
| `bjj-xx` | Kanauji (Generic) |
| `cjk-ao` | Chokwe (Angola) |
| `mrr-xx` | Maria (India) |
| `qvi-xx` | Imbabura Highland Quichua (Generic) |
| `bgp-pk` | Eastern Balochi (Pakistan) |
| `bag-xx` | Tuki (Generic) |
## MARS-Instruct
Supported in `mars-instruct`. **142 languages supported.**
| Code | Language |
| :--------------- | :------------------------ |
| `en-us` | English (USA) |
| `af-za` | Afrikaans (South Africa) |
| `am-et` | Amharic (Ethiopia) |
| `ar-ae` | Arabic (UAE) |
| `ar-bh` | Arabic (Bahrain) |
| `ar-dz` | Arabic (Algeria) |
| `ar-eg` | Arabic (Egypt) |
| `ar-iq` | Arabic (Iraq) |
| `ar-jo` | Arabic (Jordan) |
| `ar-kw` | Arabic (Kuwait) |
| `ar-lb` | Arabic (Lebanon) |
| `ar-ly` | Arabic (Libya) |
| `ar-ma` | Arabic (Morocco) |
| `ar-om` | Arabic (Oman) |
| `ar-qa` | Arabic (Qatar) |
| `ar-sa` | Arabic (Saudi Arabia) |
| `ar-sy` | Arabic (Syria) |
| `ar-tn` | Arabic (Tunisia) |
| `ar-ye` | Arabic (Yemen) |
| `az-az` | Azerbaijani (Azerbaijan) |
| `bg-bg` | Bulgarian (Bulgaria) |
| `bgc-in` | Haryanvi (Haryana, India) |
| `bho-in` | Bhojpuri (India) |
| `bn-bd` | Bengali (Bangladesh) |
| `bn-in` | Bengali (India) |
| `ca-es` | Catalan (Spain) |
| `cs-cz` | Czech (Czechia) |
| `da-dk` | Danish (Denmark) |
| `de-at` | German (Austria) |
| `de-ch` | German (Switzerland) |
| `de-de` | German (Germany) |
| `el-gr` | Greek (Greece) |
| `en-au` | English (Australia) |
| `en-ca` | English (Canada) |
| `en-gb` | English (United Kingdom) |
| `en-hk` | English (Hong Kong) |
| `en-ie` | English (Ireland) |
| `en-in` | English (India) |
| `en-ke` | English (Kenya) |
| `en-ng` | English (Nigeria) |
| `en-nz` | English (New Zealand) |
| `en-ph` | English (Philippines) |
| `en-sg` | English (Singapore) |
| `en-tz` | English (Tanzania) |
| `en-za` | English (South Africa) |
| `es-ar` | Spanish (Argentina) |
| `es-bo` | Spanish (Bolivia) |
| `es-cl` | Spanish (Chile) |
| `es-co` | Spanish (Colombia) |
| `es-cr` | Spanish (Costa Rica) |
| `es-cu` | Spanish (Cuba) |
| `es-do` | Spanish (Dominican Rep.) |
| `es-ec` | Spanish (Ecuador) |
| `es-es` | Spanish (Spain) |
| `es-gq` | Spanish (Eq. Guinea) |
| `es-gt` | Spanish (Guatemala) |
| `es-hn` | Spanish (Honduras) |
| `es-mx` | Spanish (Mexico) |
| `es-ni` | Spanish (Nicaragua) |
| `es-pa` | Spanish (Panama) |
| `es-pe` | Spanish (Peru) |
| `es-pr` | Spanish (Puerto Rico) |
| `es-py` | Spanish (Paraguay) |
| `es-sv` | Spanish (El Salvador) |
| `es-us` | Spanish (USA) |
| `es-uy` | Spanish (Uruguay) |
| `es-ve` | Spanish (Venezuela) |
| `et-ee` | Estonian (Estonia) |
| `eu-es` | Basque (Spain) |
| `fa-ir` | Persian (Iran) |
| `fi-fi` | Finnish (Finland) |
| `fr-be` | French (Belgium) |
| `fr-ca` | French (Canada) |
| `fr-ch` | French (Switzerland) |
| `fr-fr` | French (France) |
| `gl-es` | Galician (Spain) |
| `gu-in` | Gujarati (India) |
| `he-il` | Hebrew (Israel) |
| `hi-in` | Hindi (India) |
| `hr-hr` | Croatian (Croatia) |
| `hu-hu` | Hungarian (Hungary) |
| `hy-am` | Armenian (Armenia) |
| `id-id` | Indonesian (ID) |
| `is-is` | Icelandic (Iceland) |
| `it-it` | Italian (Italy) |
| `ja-jp` | Japanese (Japan) |
| `jv-id` | Javanese (ID) |
| `ka-ge` | Georgian (Georgia) |
| `kn-in` | Kannada (India) |
| `ko-kr` | Korean (South Korea) |
| `lo-la` | Lao (Laos) |
| `lt-lt` | Lithuanian (Lithuania) |
| `lv-lv` | Latvian (Latvia) |
| `mk-mk` | Macedonian (N. Macedonia) |
| `ml-in` | Malayalam (India) |
| `mn-mn` | Mongolian (Mongolia) |
| `mr-in` | Marathi (India) |
| `ms-my` | Malay (Malaysia) |
| `my-mm` | Burmese (Myanmar) |
| `nb-no` | Norwegian Bokmål (Norway) |
| `ne-np` | Nepali (Nepal) |
| `nl-be` | Dutch (Belgium) |
| `nl-nl` | Dutch (Netherlands) |
| `pl-pl` | Polish (Poland) |
| `ps-af` | Pashto (Afghanistan) |
| `pt-br` | Portuguese (Brazil) |
| `pt-pt` | Portuguese (Portugal) |
| `ro-ro` | Romanian (Romania) |
| `ru-ru` | Russian (Russia) |
| `si-lk` | Sinhala (Sri Lanka) |
| `sk-sk` | Slovak (Slovakia) |
| `sl-si` | Slovenian (Slovenia) |
| `sq-al` | Albanian (Albania) |
| `sr-rs` | Serbian (Serbia) |
| `sv-se` | Swedish (Sweden) |
| `sw-ke` | Swahili (Kenya) |
| `sw-tz` | Swahili (Tanzania) |
| `ta-in` | Tamil (India) |
| `ta-lk` | Tamil (Sri Lanka) |
| `ta-my` | Tamil (Malaysia) |
| `ta-sg` | Tamil (Singapore) |
| `te-in` | Telugu (India) |
| `th-th` | Thai (Thailand) |
| `tr-tr` | Turkish (Turkey) |
| `uk-ua` | Ukrainian (Ukraine) |
| `ur-in` | Urdu (India) |
| `ur-pk` | Urdu (Pakistan) |
| `vi-vn` | Vietnamese (Vietnam) |
| `zh-cn` | Chinese (China) |
| `zh-cn-henan` | Chinese (China, Henan) |
| `zh-cn-liaoning` | Chinese (China, Liaoning) |
| `zh-cn-shaanxi` | Chinese (China, Shaanxi) |
| `zh-cn-shandong` | Chinese (China, Shandong) |
| `zh-cn-sichuan` | Chinese (China, Sichuan) |
| `zh-hk` | Chinese (Hong Kong) |
| `pa-in` | Punjabi (India) |
| `ar-xa` | Arabic (Pan-Arabic) |
| `tl-ph` | Tagalog (Philippines) |
| `es-xl` | Spanish (Latin America) |
| `or-in` | Odia (India) |
| `sd-in` | Sindhi (India) |
| `be-by` | Belarusian (Belarus) |
# MARS 8 TTS Models
Source: https://docs.camb.ai/models
The **MARS 8** family consists of **zero-shot, multilingual Text-to-Speech (TTS) models** designed to cover a wide range of production needs. Each model varies in **latency, quality, controllability, and ideal use case**, allowing you to choose the right fit for your application.
Plus, MARS-Pro and MARS-Flash models are available on all [major cloud providers.](/custom-cloud-providers)
## Model Summary
| Model | Sample Rate | Notes |
| :---------------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **mars-8.1-flash-beta** | **48kHz** | Beta MARS 8.1 model, optimized for faster generation. Try this model when quality is the priority, as it may perform much better for pronunciation, expressiveness with high-pitch references, overall prosody, accent control, accent coverage, and quality across different accents. |
| **mars-8.1-pro-beta** | **48kHz** | Beta MARS Pro model. Try this model when quality is the priority, as it may perform much better for pronunciation, expressiveness with high-pitch references, overall prosody, accent control, accent coverage, and quality across different accents. |
| **mars-flash** | **22.05kHz/48kHz** | Ultra-low latency TTS for real-time agents, call center agents, and live conversational assistants. |
| **mars-pro** | **48kHz** | Balanced speed and fidelity for expressive real-time speech, dubbing, audiobooks, and digital media. |
| **mars-instruct** | **22.05kHz** | Director-level emotional and prosodic control with embedded expressive text tags. |
## MARS-8.1-Flash-Beta (48khz)
**Faster preview access to MARS 8.1 quality improvements**
* **Model ID:** `mars-8.1-flash-beta`
* **Primary Use Cases:**
* Faster evaluation of MARS 8.1 generation quality
* Lower-latency workflows that still need stronger accent handling
* Comparing output quality and speed against `mars-flash` and `mars-8.1-pro-beta`
* **Quality Improvements:** Provides the same quality as MARS 8.1, including much better quality across different accents, while being faster than `mars-8.1-pro-beta`.
* **Notes:** This is a beta model. For both MARS 8.1 beta models, your target language should use a reference voice in the same language and accent for the best results. Test with your target voices, languages, accents, and audio formats before using either beta model in production workflows.
## MARS-8.1-Pro-Beta (48khz)
**Preview access to the newest Pro-quality speech model**
* **Model ID:** `mars-8.1-pro-beta`
* **Primary Use Cases:**
* Evaluating the latest MARS Pro generation quality
* High-fidelity TTS experiments before production rollout
* Comparing output quality against `mars-pro`
* **Quality Improvements:** May perform much better than `mars-pro` for pronunciation, overall prosody, accent control, accent coverage, and quality across different accents. It is also designed to improve expressiveness, especially for high-pitch reference voices.
* **Notes:** This is a beta model. For MARS 8.1 beta models, your target language should use a reference voice in the same language and accent for the best results. Test it with your target voices, languages, accents, and audio formats before using it in production workflows.
## MARS-Flash (22.05khz/48khz)
**Ultra-low latency TTS for real-time agents and assistants**
* **Parameters:** 600M
* **TTFB:** As low as **150 ms** on certain GPUs like Blackwell
* **Primary Use Cases:**
* Agentic conversations
* Call center agents
* Live conversational assistants
## MARS-Pro (48khz)
**Balanced speed and fidelity for expressive real-time speech**
* **Parameters:** 600M
* **TTFB:** **800 ms – 2 s**
* **Primary Use Cases:**
* Real-time translation with voice and emotion transfer
* Expressive dubbing
* Audiobooks and digital media
* **Notes:** Delivers best overall performance when speed is not the primary constraint, especially with short or challenging reference audio.
## MARS-Instruct (22.05khz)
**Director-level emotional and prosodic control**
* **Parameters:** 1.2B
* **TTFB:** Higher latency (not intended for real-time use)
* **Primary Use Cases:**
* High-end TV and film production
* Movie dubbing and post-production editing
* **Capabilities:**
* Independent control of speaker identity and prosody
* Style and emotion can be tuned using both:
* A reference audio sample
* A textual description of desired prosody
## MARS-Nano
**Highly efficient TTS for on-device deployment**
* **Parameters:** 50M
* **TTFB:** **500 ms – 2 s**, depending on available compute
* **Primary Use Cases:**
* On-device applications
* Environments with strict memory and compute constraints
* **Deployment Notes:** Currently deployed with partners and providers such as [**Broadcom**](https://www.camb.ai/blog-post/broadcom-parters-with-camb-ai).
### Tips For Best Results:
* For texts with numbers expand the numbers to words. For example, instead of "123" to "one hundred twenty three" or "one two three" as you need.
* For code-switched sentences, perform transliteration to convert the text to your chosen TTS language. We're improving the model to handle above nuances better, but we find that practically most LLM outputs feeding in already have the conversions. We've focused more on other parameters related to quality.
### Advanced Customization
Fine-tune the audio with additional parameters to control the performance, style, and quality of the generated speech.
These can be sent in the payload. More details available in the [API Reference](/api-reference/endpoint/create-tts-stream).
* **`user_instructions`**: Guide the voice's delivery (e.g., "Warm, clear, and conversational"). Only supported with `mars-instruct`.
* **`output_configuration`**: Set the audio format (`wav`, `mp3`), and apply enhancements.
* **`voice_settings`**: Enhance reference audio quality, maintain the source accent, or adjust the speaking rate.
* **`inference_options`**: Adjust stability, temperature, and speaker similarity for unique results.
## Language Support
**MARS-8.1-Flash-Beta, MARS-8.1-Pro-Beta, MARS-Flash, MARS-Pro, and MARS-Instruct** are released across multiple languages, collectively covering **99% of the world's speaking population**.
Coverage varies by model:
| Model | Languages |
| :----------------------------------------- | :-------- |
| `mars-flash`, `mars-pro` | 33 |
| `mars-8.1-flash-beta`, `mars-8.1-pro-beta` | 312 |
| `mars-instruct` | 142 |
See the full per-model locale list in [Language Support](/language-support).
# Open Source
Source: https://docs.camb.ai/open-source
Explore our state-of-the-art open source speech models.
At Camb AI, we believe in democratizing access to powerful voice technology. We've released significant portions of our research as open-source models, allowing the community to build, experiment, and innovate.
## MARS 6 Turbo
**MARS6: A Small and Robust Hierarchical-Codec Text-to-Speech Model**
MARS 6 Turbo represents the latest evolution in our open-source speech synthesis technology. It delivers robust performance with a hierarchical codec architecture, optimized for efficiency without compromising on quality.
### Resources
* **Demo & Samples**: [Project Page](https://camb-ai.github.io/mars6-turbo/)
* **Research Paper**: [arXiv:2501.05787](https://arxiv.org/abs/2501.05787)
* **Website**: [https://camb.ai](https://camb.ai)
Access the model weights, inference code, and technical documentation.
## MARS 5
[MARS 5](https://github.com/camb-ai/mars5-tts) remains a powerful tool in our open-source suite, offering a transformer-based architecture for flexible speech generation.
### Key Features
* **Flexible Prosody**: Context-aware rhythm and intonation.
* **Voice Cloning**: Zero-shot cloning with short reference audio.
* **Multilingual Support**: Diverse language and accent capabilities.
Check out the MARS 5 code and models.
## Community & Contribution
We welcome contributions! Whether it's adding support for new languages, optimizing inference, or building new applications on top of MARS, join us on GitHub to shape the future of open-source speech AI.
# Installation
Source: https://docs.camb.ai/other-products/chatterbox/installation
Install the Chatterbox Desktop App for Windows from CAMB AI Studio.
This guide walks you through installing the Chatterbox Desktop App for Windows from CAMB AI Studio. Follow each step in order — the process is quick and safe, and you can always go back if you need to review a setting.
A system reboot is **mandatory** at the end of the installation so that the virtual audio drivers can be correctly installed and activated. If you skip the reboot, the app will not function as expected.
## Step 1 — Open CAMB AI Studio in your browser
1. Open your preferred web browser and sign in to [CAMB AI Studio](https://studio.camb.ai).
2. In the left-hand sidebar, scroll down to the **Platform** section.
3. Click **Integrations** to open the list of available integrations for your workspace.
## Step 2 — Download the Chatterbox Desktop App
1. On the Integrations page, find the **Chatterbox Desktop App** card.
2. Under the description, click the **Windows** button.
3. Your browser will begin downloading the Chatterbox installer. Wait until the download completes.
## Step 3 — Open the installer
1. Open File Explorer and navigate to your **Downloads** folder.
2. Locate the file named `Chatterbox-1.6.7-setup.exe` (the version number may differ).
3. Double-click the file to launch the installer. If Windows asks for permission, click **Yes**.
## Step 4 — Choose the installer language
A small window titled **Installer Language** appears. Make sure **English** (or your preferred language, if available) is selected, then click **OK**.
## Step 5 — Start the Chatterbox Setup Wizard
The Chatterbox Setup welcome screen explains that the setup will guide you through the installation process. Click **Next** to proceed.
## Step 6 — Review and accept the License Agreement
1. Review the terms on the **License Agreement** page.
2. Select **I accept the terms of the License Agreement**.
3. Click **Next** to continue.
## Step 7 — Confirm the installation location
The **Choose Install Location** screen shows where Chatterbox will be installed — by default `C:\Program Files\Chatterbox\`. For most users, keeping the default location is recommended.
If you need to change it, click **Browse…** and select a different folder. When you're satisfied, click **Next**.
## Step 8 — Configure Start Menu shortcuts
On the **Choose Start Menu Folder** screen, decide how Chatterbox appears in your Start Menu.
* The default folder name **Chatterbox** is usually best.
* If you prefer not to create any Start Menu shortcuts, check **Do not create shortcuts**.
When ready, click **Install** to begin the installation.
## Step 9 — Wait while installation completes
The installer now shows an **Installing** screen with a progress bar. Please wait while Chatterbox and its components (including the required audio drivers) are copied and configured. You don't need to do anything on this screen.
## Step 10 — Complete setup and reboot
When installation is complete, a **Completing Chatterbox Setup** screen appears with a prompt to restart your computer.
1. Select **Reboot now** (recommended).
2. Click **Finish** to close the installer and restart your computer.
Restarting your system is required so that the virtual audio drivers used by Chatterbox are correctly installed and activated.
## What's next
After your computer reboots:
* Open Chatterbox from the Start Menu or desktop shortcut.
* Sign in with your CAMB AI Studio account to connect Chatterbox to your workspace.
* Continue to [Verify your setup](/other-products/chatterbox/setup-verification) to confirm the audio drivers are working before joining a live meeting.
If anything doesn't look as described above, you can safely close the installer and start again from your Downloads folder.
# Overview
Source: https://docs.camb.ai/other-products/chatterbox/overview
Real-time multilingual translation for your live meetings on Windows.
Chatterbox is the CAMB AI desktop app that brings live, multilingual translation into your everyday meetings. It installs a pair of virtual audio drivers on Windows, sits between your microphone and any meeting platform (Zoom, Microsoft Teams, Google Meet, and more), and translates your speech in real time so participants hear you in their preferred language.
## How it works
1. You speak into your normal microphone in your **"I Speak"** language.
2. Chatterbox transcribes, translates, and re-synthesizes the audio in the **"They Hear"** language.
3. The translated audio is routed through the **Chatterbox Virtual Microphone**, which the meeting platform picks up as your mic input.
Your participants hear you naturally in their language without installing anything on their end.
## Requirements
* **Operating system**: Windows 10 or 11.
* **CAMB AI Studio account**: sign in at [studio.camb.ai](https://studio.camb.ai) to download the installer and authenticate the app.
* **Headphones or earphones**: required during live sessions to prevent feedback loops between your speakers and microphone.
* **A reboot after install**: the virtual audio drivers only activate after a system restart.
## Get started
Step-by-step Windows installer walkthrough.
Confirm virtual audio drivers are installed and working.
Configure languages, audio devices, and start a live session.
# Realtime WebSocket events
Source: https://docs.camb.ai/other-products/chatterbox/realtime-websocket-events
Client and server event contracts for the Realtime WebSocket API.
The Realtime WebSocket API creates a real-time speech translation session over a single WebSocket connection. The client sends a session configuration first, then streams microphone audio with JSON events that contain base64-encoded audio. The server responds with session lifecycle events, transcripts, translated text, and translated audio.
For the interactive WebSocket playground, see [Realtime (WebSocket)](/api-reference/websockets/realtime).
## Endpoint
```http theme={null}
GET /v1/realtime?mode=fast
Host: realtime.camb.ai
x-api-key:
```
The request upgrades to a WebSocket connection. The `mode` query parameter is optional.
| Mode | Notes |
| ------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `fast` | Default. Accepts audio almost immediately and translates with the lowest latency, but supports fewer languages. |
| `slow` | Supports the full language list and translates more accurately, at the cost of a 30s+ cold boot before the session is ready. |
If `session.update.session.mode` is omitted, the server uses the `mode` query parameter. If both are omitted, the server uses `fast`.
**Migrating from `model`.** `mode` replaced an earlier `model` parameter that took the engine codenames `lilac`, `violet`, `iris`, and `orchid`. Both the old parameter and the old values are still accepted, so existing integrations keep working — they resolve as follows, and the server logs a deprecation warning.
| Retired value | Resolves to |
| --------------------------- | ----------- |
| `iris` | `fast` |
| `lilac`, `violet`, `orchid` | `slow` |
`mode` wins if you send both. A value that was never valid is still rejected — the compatibility mapping covers the four codenames above, not arbitrary strings.
## Session lifecycle
Connect to `wss://realtime.camb.ai/v1/realtime`. Send your API key in the `x-api-key` request header when your WebSocket client supports custom headers.
The first WebSocket message must be a JSON `session.update` event. The server waits up to 10 seconds for this initial event.
After authorization and activation, the server sends `session.created`, followed by `session.updated`.
Send base64-encoded audio chunks with `input_audio_buffer.append`. The server forwards decoded audio bytes into the realtime pipeline.
The server emits completed input transcripts, translated text deltas, final translated text, translated audio chunks, and audio completion events.
Only text WebSocket messages are parsed as realtime events. Binary messages and Pong frames are ignored. Ping frames receive Pong replies.
## Authentication
Prefer the `x-api-key` WebSocket request header.
```http theme={null}
x-api-key:
```
You can also send credentials in the initial `session.update` event.
```json API key auth theme={null}
{
"type": "session.update",
"session": {
"mode": "fast",
"source_language": "en-US",
"target_language": "de-DE",
"output_modalities": ["text", "audio"]
},
"auth": {
"api_key": ""
}
}
```
If the request header and `auth` object are both present, the request header credential is used.
## Limits
| Limit | Value |
| ------------------------------------------------------------- | -------------------------- |
| Initial `session.update` timeout | 10 seconds |
| Maximum client event text size | 1 MiB |
| Maximum decoded audio payload per `input_audio_buffer.append` | 256 KiB |
| Audio encoding in `input_audio_buffer.append.audio` | Base64-encoded audio bytes |
## Session configuration
Send the active session settings in `session.update.session`.
```json theme={null}
{
"mode": "fast",
"source_language": "en-US",
"target_language": "de-DE",
"output_modalities": ["text", "audio"]
}
```
| Field | Type | Required | Notes |
| ------------------- | --------- | -------- | ------------------------------------------------------------------------------ |
| `mode` | string | No | Defaults to the `mode` query parameter, then `fast`. Must be `fast` or `slow`. |
| `source_language` | string | Yes | Source language tag, for example `en-US`. |
| `target_language` | string | Yes | Target language tag, for example `de-DE`. |
| `output_modalities` | string\[] | No | Defaults to `["text", "audio"]`. |
## Client events
| Event | When to send it | Support |
| --------------------------- | -------------------------------- | ---------------------------- |
| `session.update` | First message on the connection. | Required for activation. |
| `input_audio_buffer.append` | After the session is active. | Supported. |
| `input_audio_buffer.clear` | Not available in this version. | Recognized, returns `error`. |
| `input_audio_buffer.commit` | Not available in this version. | Recognized, returns `error`. |
| `response.cancel` | Not available in this version. | Recognized, returns `error`. |
### `session.update`
Initializes the realtime session. This must be the first client event.
```json theme={null}
{
"type": "session.update",
"session": {
"mode": "fast",
"source_language": "en-US",
"target_language": "de-DE",
"output_modalities": ["text", "audio"]
}
}
```
After activation, sending another `session.update` is recognized but not supported. The server responds with an `error` event.
```json theme={null}
{
"type": "error",
"error": {
"message": "session.update after activation is not supported in this version"
}
}
```
### `input_audio_buffer.append`
Appends audio bytes to the realtime input stream.
```json theme={null}
{
"type": "input_audio_buffer.append",
"audio": ""
}
```
The server base64-decodes `audio` and forwards the decoded bytes into the realtime pipeline. Each decoded payload can be up to 256 KiB.
### Unsupported client events
These events are recognized so clients can receive a structured error instead of silent failure.
```json theme={null}
{
"type": "input_audio_buffer.clear"
}
```
Server response:
```json theme={null}
{
"type": "error",
"error": {
"message": "input_audio_buffer.clear is not supported in this version"
}
}
```
```json theme={null}
{
"type": "input_audio_buffer.commit"
}
```
Server response:
```json theme={null}
{
"type": "error",
"error": {
"message": "input_audio_buffer.commit is not supported in this version"
}
}
```
```json theme={null}
{
"type": "response.cancel"
}
```
Server response:
```json theme={null}
{
"type": "error",
"error": {
"message": "response.cancel is not supported in this version"
}
}
```
## Server events
| Event | Description |
| ------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `session.created` | Sent after the server authorizes, starts, and activates the realtime session. |
| `session.updated` | Sent immediately after `session.created` with the active session configuration. |
| `conversation.item.input_audio_transcription.completed` | Sent when the pipeline produces a completed user transcript. |
| `response.text.delta` | Sent for incremental assistant translation text. Deltas are additive for the current response. |
| `response.text.done` | Sent when the final assistant translation text is available. |
| `response.audio.delta` | Sent when synthesized output audio bytes are available. |
| `response.audio.done` | Sent when the current assistant audio response is complete. |
| `error` | Sent for recognized unsupported client events and billing stop decisions. |
### Session events
`session.created` includes the durable realtime session ID.
```json theme={null}
{
"type": "session.created",
"session": {
"id": "2a4d3cb0-ff62-4e02-a37c-9fcf4e49c8cc",
"mode": "fast",
"source_language": "en-US",
"target_language": "de-DE",
"output_modalities": ["text", "audio"]
}
}
```
`session.updated` confirms the active session configuration.
```json theme={null}
{
"type": "session.updated",
"session": {
"mode": "fast",
"source_language": "en-US",
"target_language": "de-DE",
"output_modalities": ["text", "audio"]
}
}
```
| Field | Type | Notes |
| --------------------------- | ----------- | ---------------------------------------------------------- |
| `session.id` | UUID string | Durable realtime session ID. Present on `session.created`. |
| `session.mode` | string | Active mode, `fast` or `slow`. |
| `session.source_language` | string | Source language tag. |
| `session.target_language` | string | Target language tag. |
| `session.output_modalities` | string\[] | Active output modalities. |
### Transcript and response events
```json theme={null}
{
"type": "conversation.item.input_audio_transcription.completed",
"transcript": "Hello, how are you?"
}
```
```json theme={null}
{
"type": "response.text.delta",
"delta": "Guten"
}
```
```json theme={null}
{
"type": "response.text.done",
"text": "Guten Tag, wie geht es Ihnen?"
}
```
```json theme={null}
{
"type": "response.audio.delta",
"delta": ""
}
```
```json theme={null}
{
"type": "response.audio.done"
}
```
### Errors and billing stops
The server sends `error` for recognized but unsupported client events.
```json theme={null}
{
"type": "error",
"error": {
"message": "input_audio_buffer.commit is not supported in this version"
}
}
```
Billing can also stop a session. In that case, the server sends an `error` event whose `error.message` is the billing close reason, then ends the realtime loop. Active sessions are charged in billing windows and finalized on close, failure, or billing stop.
## Example message flow
```json Client: session.update theme={null}
{
"type": "session.update",
"session": {
"mode": "fast",
"source_language": "en-US",
"target_language": "de-DE",
"output_modalities": ["text", "audio"]
}
}
```
```json Server: session.created theme={null}
{
"type": "session.created",
"session": {
"id": "2a4d3cb0-ff62-4e02-a37c-9fcf4e49c8cc",
"mode": "fast",
"source_language": "en-US",
"target_language": "de-DE",
"output_modalities": ["text", "audio"]
}
}
```
```json Server: session.updated theme={null}
{
"type": "session.updated",
"session": {
"mode": "fast",
"source_language": "en-US",
"target_language": "de-DE",
"output_modalities": ["text", "audio"]
}
}
```
```json Client: append audio theme={null}
{
"type": "input_audio_buffer.append",
"audio": ""
}
```
```json Server: transcript theme={null}
{
"type": "conversation.item.input_audio_transcription.completed",
"transcript": "Hello, how are you?"
}
```
```json Server: text delta theme={null}
{
"type": "response.text.delta",
"delta": "Guten Tag"
}
```
```json Server: text done theme={null}
{
"type": "response.text.done",
"text": "Guten Tag, wie geht es Ihnen?"
}
```
```json Server: audio delta theme={null}
{
"type": "response.audio.delta",
"delta": ""
}
```
```json Server: audio done theme={null}
{
"type": "response.audio.done"
}
```
# Verify your setup
Source: https://docs.camb.ai/other-products/chatterbox/setup-verification
Confirm that Chatterbox and its virtual audio drivers are installed and working.
After completing the installation and rebooting your computer, it's a good idea to verify that Chatterbox and its **Virtual Audio Drivers** are installed and working correctly. The app includes a guided test that walks you through this in a few minutes.
## Step 1 — Open Chatterbox and start the test
1. Launch the **Chatterbox Desktop App** from your Start Menu or desktop.
2. Sign in with your CAMB AI Studio account if prompted.
3. On the **Home** screen, confirm that your **I Speak** and **They Hear** languages look reasonable — you can adjust them later.
4. At the bottom of the window, click **Test Setup** to start an automatic check of your audio configuration.
## Step 2 — Verify that audio drivers are installed
A window titled **Audio Device Setup** appears on the **Drivers Test** step.
1. In the **Verify Audio Drivers** section, click **Verify**.
2. The app checks whether the required Virtual Audio Drivers were correctly installed during setup and the reboot.
3. Wait a few moments while the check runs.
## Step 3 — Confirm driver installation success
When verification completes, you should see a green success message such as **Audio Drivers Installed Successfully** along with a green checkmark. This means your system has the required audio drivers installed and configured, and Chatterbox can route audio correctly through them.
Click **Next Step** to continue to the audio functionality test.
## Step 4 — Test audio with the installed drivers
The next screen, **Audio Test**, lets you confirm the drivers are actually working, not just installed.
1. Ensure the speaker device at the top is set to the speakers or headphones you are currently using.
2. Click **Test Driver 1**. You should hear a short test tone. A green **Driver 1 Working** message confirms the first audio path is functioning.
3. Click **Test Driver 2**. Again, you should hear a short test tone. A green **Driver 2 Working** message confirms the second audio path is also functioning.
4. Once both tests succeed, click **Complete** to close the Audio Device Setup window.
With both driver tests passing, your Virtual Audio Drivers are correctly installed and fully operational. You're ready to start using Chatterbox in live meetings.
Next, head to [Using Chatterbox](/other-products/chatterbox/using-chatterbox) to configure your languages, audio devices, and join your first session.
# Using Chatterbox
Source: https://docs.camb.ai/other-products/chatterbox/using-chatterbox
Configure languages, audio devices, and start a live translated session.
Once installation and verification are complete, you can start using Chatterbox in your live meetings. The steps below help you get the best possible audio quality and translation performance.
## Step 1 — Wear earphones or headphones
Put on earphones or headphones **before** starting your session. This:
* Prevents audio feedback and echo, where your speakers feed back into your microphone.
* Avoids audio looping, where translated audio is re-captured and re-translated.
* Avoids degraded performance and noisy audio that come from using built-in laptop speakers.
Using only built-in laptop speakers can cause feedback loops, degraded audio quality, and confusion for meeting participants.
## Step 2 — Configure language settings
* **I Speak**: Set this to the language you will actually speak during the meeting (for example, *English (United States)*). Chatterbox listens in this language to understand what you say.
* **They Hear**: Set this to the language your audience should hear (for example, *Spanish (Spain)*). Chatterbox translates your speech from **I Speak** into **They Hear**.
## Step 3 — Select the correct audio devices
**Confirm your microphone device.** In Chatterbox, set the microphone to your physical mic — for example:
* Your USB headset microphone, or
* Your external microphone, or
* Your laptop microphone if no other device is available.
Using the right mic ensures your voice is captured clearly for accurate translation.
**Confirm your output (speaker) device.** Set the output to the earphones or headphones you are wearing. If a different device (like monitor speakers or unused outputs) is selected, you may not hear the translated audio or it may be very quiet.
Taking a moment here prevents common issues like "no one can hear me" or "I don't hear anything."
## Step 4 — Join your meeting using Chatterbox Virtual Audio
1. Open your preferred meeting platform (Zoom, Microsoft Teams, Google Meet, etc.).
2. In the meeting's audio settings, set your **microphone** to the Chatterbox virtual device — typically named **Chatterbox Virtual Microphone**.
3. Keep your **speakers** set to the device you normally use (your headphones or earphones).
**Why this is important:** selecting the Chatterbox Virtual Microphone lets the meeting platform receive audio that has been processed and translated by Chatterbox, rather than your raw microphone feed. This is how Chatterbox delivers live translated speech to your participants.
### Optional — Reset Windows audio devices if needed
After installing Chatterbox, Windows may automatically change your default audio devices. If you notice unusual audio behavior in other apps (no sound, or sound coming from the wrong device), reset your defaults:
1. Right-click the speaker icon in the taskbar and choose **Sound settings**.
2. Check both **Input** and **Output** devices.
3. Set **Input** to your usual microphone (or headset mic).
4. Set **Output** to your usual speakers or headphones.
This ensures your computer's audio behaves as expected outside of Chatterbox, while Chatterbox continues to use its virtual devices during sessions.
## Step 5 — Start a Chatterbox session
1. Review your languages and audio devices one last time.
2. Click **Start Session** in the center of the Chatterbox window.
3. Begin speaking normally in your meeting.
Once the session is active, Chatterbox will listen to your speech, translate it, and output translated audio in real time according to your **I Speak** and **They Hear** settings. Your participants will hear you in their selected language through the Chatterbox Virtual Microphone.
With these steps complete, Chatterbox is configured for live meetings and optimized for clear audio and accurate translation.
# Next.js (Page Router)
Source: https://docs.camb.ai/other-products/website-translation/nextjs-page-router
Configure CAMB AI Website Translator in a Next.js project using the Page Router.
This step-by-step guide walks you through configuring Website Translation in a Next.js project that uses the **Page Router**. It includes the exact `Script` configuration, best practices, and troubleshooting tips.
## Step 1 — Create your Website Configuration
In CAMB AI Studio, open the **Website Configuration** form and fill in the following:
* **Name** — A friendly name for your project (e.g., `My website`).
* **Domain** — Your production domain (e.g., `example.com`).
* **Redis Cache URL (Secure)** — A secure `rediss://` connection string for caching translations. See [Set up Redis with Upstash](/other-products/website-translation/redis-cache) if you don't have one.
* **Translate from** — The source language for your content.
* **Translate to** — One or more target languages.
Click **Create Website** to generate your API key.
## Step 2 — Add the script in Next.js
Integrate the script using Next.js's [`next/script`](https://nextjs.org/docs/pages/api-reference/components/script) in `pages/_app.tsx`. Make sure the `data-api-key` attribute comes **before** the `strategy` prop, exactly as shown below.
```tsx pages/_app.tsx theme={null}
import Script from "next/script";
import type { AppProps } from "next/app";
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<>
{/* Website Translate Script */}
>
);
}
```
**Why this works:** The script loads after the page becomes interactive, minimizing render-blocking. The `data-api-key` attribute securely passes your key to the client script.
### Optional — Manage the API key via environment variable
If you prefer not to hard-code the key, expose it as `NEXT_PUBLIC_TRANSLATOR_API_KEY` and pass it to the `Script` tag:
```bash .env.local theme={null}
NEXT_PUBLIC_TRANSLATOR_API_KEY=your-api-key
```
```tsx pages/_app.tsx theme={null}
```
## Step 3 — Deploy and verify
1. Deploy your Next.js app as usual (Vercel, Netlify, or your preferred platform).
2. Open your site in a browser and confirm that a **translation dropdown appears automatically**.
3. Switch languages and verify page text is translated without layout shifts or flashes.
## Best practices for a great UX
* **Warm the cache.** After deployment, visit your key pages yourself and wait for the initial translation to complete so future visitors get instant translations.
* **Keep phrases intact.** Avoid splitting single words or short phrases into many tiny elements — translation accuracy is higher when the translator sees whole sentences.
### Exclude content from translation
Use HTML attributes or classes to skip specific elements:
```html theme={null}
BrandName
CodeSnippet()
```
### Style the translation dropdown
Customize the dropdown via CSS variables:
```css theme={null}
:root {
/* Position */
--tl-position: fixed;
--tl-bottom: 24px;
--tl-right: 24px;
--tl-top: auto;
--tl-left: auto;
--tl-z-index: 9999;
/* Appearance */
--tl-bg: #333;
--tl-bg-hover: #555;
--tl-color: #fff;
--tl-border: none;
--tl-border-radius: 4px;
--tl-box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
/* Typography */
--tl-font-family: "Inter", sans-serif;
--tl-font-size: 14px;
--tl-font-weight: 500;
--tl-line-height: 1;
/* Spacing */
--tl-padding: 12px 16px;
--tl-margin: 0;
--tl-min-width: 120px;
--tl-width: auto;
--tl-height: auto;
/* Options */
--tl-option-bg: #333;
--tl-option-color: #fff;
--tl-option-padding: 8px 12px;
/* Loading state */
--tl-loading-opacity: 0.7;
--tl-loading-icon: "⟳";
--tl-loading-margin: 8px;
--tl-loading-duration: 1s;
/* Focus */
--tl-outline: 2px solid #007acc;
--tl-outline-offset: 2px;
/* Transition */
--tl-transition: all 0.2s ease;
}
```
## Troubleshooting
Verify that `pages/_app.tsx` includes the `Script` block and that your API key is correct. Hard-refresh the page (Cmd/Ctrl + Shift + R) and check the browser console for script errors.
The first pass may be warming the cache. Visit the page once and try again — subsequent loads will pull translations from Redis.
Rarely, browser extensions may block third-party scripts. Test in a clean browser profile or incognito window.
## Security & configuration notes
* **Only use the official script source:** `https://storage.googleapis.com/website-translation-script/translator.js`.
* **Prefer environment variables** (`NEXT_PUBLIC_TRANSLATOR_API_KEY`) for manageability across environments.
* **Use a secure Redis URL.** Your Redis Cache URL must use `rediss://` (TLS-encrypted) — never plain `redis://`.
# Overview
Source: https://docs.camb.ai/other-products/website-translation/overview
Translate your entire website into multiple languages with a single script tag.
CAMB AI **Website Translation** lets you add multilingual support to your site by dropping in a single `