Use this file to discover all available pages before exploring further.
The official PHP SDK for Camb.ai provides access to text-to-speech, dubbing, translation, transcription, audio separation, voice cloning, and audio generation through CambAIClient for common workflows and generated API classes for the rest of the HTTP surface. The SDK is synchronous: call APIs from your PHP process or queue workers and poll until asynchronous jobs finish.
Get your API key from Camb.ai Studio and read it from an environment variable so it never appears in source control.CambAIClient wires TTS (via a provider), Text-to-Voice, Text-to-Audio, and Dubbing. Other endpoints use generated *Api classes with a shared Configuration and Guzzle client. There is no separate async client in PHP: run blocking calls in requests or workers.
<?phprequire_once __DIR__ . '/vendor/autoload.php';use Camb\Ai\CambAIClient;use Camb\Ai\Configuration;use GuzzleHttp\Client;$client = new CambAIClient(getenv('CAMB_API_KEY'));$config = Configuration::getDefaultConfiguration()->setApiKey('x-api-key', getenv('CAMB_API_KEY'));$httpClient = new Client(['timeout' => 300.0]);
Load CAMB_API_KEY from a .env file during local development with vlucas/phpdotenv or your frameworkâs env layer.
The sections below that use $httpClient and $config assume you built them as shown. CambAIClient already applies the same API key and timeout internally.
Camb.ai offers MARS models tuned for different quality and latency requirements. Pass speech_model on streaming payloads using CreateStreamTTSRequestPayload constants or string literals. If you omit it, the API applies its default model.
Model
Sample Rate
Best For
mars-8.1-flash-beta
48 kHz
Faster MARS 8.1 generation; same quality improvements as mars-8.1-pro-beta
mars-8.1-pro-beta
48 kHz
Improved pronunciation, expressiveness, and prosody over mars-pro
mars-flash
22.05 kHz
Low-latency real-time applications and conversational AI
mars-pro
48 kHz
High-fidelity audio production and long-form content
mars-instruct
22.05 kHz
Fine-grained tone and style control via text instructions
The tab snippets below reuse $client from Quick Start.
MARS Flash
MARS Pro
MARS Instruct
$payload = new CreateStreamTTSRequestPayload();$payload->setText('Hey, I can respond much faster.');$payload->setVoiceId(147320);$payload->setLanguage(CreateStreamTTSRequestPayload::LANGUAGE_EN_US);$payload->setSpeechModel(CreateStreamTTSRequestPayload::SPEECH_MODEL_MARS_FLASH);$payload->setOutputConfiguration($outputConfig);$stream = $client->tts()->tts($payload);
$payload = new CreateStreamTTSRequestPayload();$payload->setText('High-fidelity audio for production use.');$payload->setVoiceId(147320);$payload->setLanguage(CreateStreamTTSRequestPayload::LANGUAGE_EN_US);$payload->setSpeechModel(CreateStreamTTSRequestPayload::SPEECH_MODEL_MARS_PRO);$payload->setOutputConfiguration($outputConfig);$stream = $client->tts()->tts($payload);
$payload = new CreateStreamTTSRequestPayload();$payload->setText('[warm, friendly] Great to meet you!');$payload->setVoiceId(147320);$payload->setLanguage(CreateStreamTTSRequestPayload::LANGUAGE_EN_US);$payload->setSpeechModel(CreateStreamTTSRequestPayload::SPEECH_MODEL_MARS_INSTRUCT);$payload->setUserInstructions('Speak warmly and with enthusiasm.');$payload->setOutputConfiguration($outputConfig);$stream = $client->tts()->tts($payload);
For beta models, pass the string on the payload when no constant exists:
Upload a reference clip as SplFileObject. Set Gender using the numeric enum values exposed on the model class (for example Gender::NUMBER_1). Optional enhance_audio helps noisy recordings.
End-to-end dubbing takes a public video URL, translates the track, and synthesizes speech that matches the speaker. Submit the job, poll status, then read URLs from the dubbing result.
Translation accepts an ordered list of strings and returns translations in the same order. Submit a job, poll getTranslationTaskStatusTranslateTaskIdGet(), then load results with getTranslationResultTranslationResultRunIdGet().
<?phprequire_once __DIR__ . '/vendor/autoload.php';use Camb\Ai\Api\TranslationApi;use Camb\Ai\Configuration;use Camb\Ai\Model\CreateTranslationRequestPayload;use Camb\Ai\Model\Languages;use Camb\Ai\Model\TaskStatus;use GuzzleHttp\Client;$config = Configuration::getDefaultConfiguration()->setApiKey('x-api-key', getenv('CAMB_API_KEY'));$httpClient = new Client(['timeout' => 300.0]);$translationApi = new TranslationApi($httpClient, $config);$payload = new CreateTranslationRequestPayload();$payload->setTexts(['Hello, how are you?', 'Welcome to Camb.ai.']);$payload->setSourceLanguage(Languages::EN_US);$payload->setTargetLanguage(Languages::FR_FR);$submit = $translationApi->createTranslationTranslatePost($payload);$taskId = $submit->task_id;while (true) { sleep(2); $status = $translationApi->getTranslationTaskStatusTranslateTaskIdGet($taskId); if ($status->getStatus() === TaskStatus::SUCCESS) { $runId = $status->getRunId(); $result = $translationApi->getTranslationResultTranslationResultRunIdGet($runId); foreach ($result->getTexts() as $text) { echo $text . PHP_EOL; } break; } if ($status->getStatus() === TaskStatus::ERROR) { break; }}
createTranslationTranslatePost() processes every string in texts in a single job and preserves ordering in the result. The OpenAPI client types this response as mixed, so the JSON-decoded object exposes task_id as a property rather than getTaskId().
Send audio or video by URL or as an uploaded file. Poll getTranscriptionTaskStatusTranscribeTaskIdGet(), then call getTranscriptionResultTranscriptionResultRunIdGet() with optional word-level timestamps.
Separation splits a mixed recording into stems. Upload media with createAudioSeparationAudioSeparationPost(), poll getAudioSeparationStatusAudioSeparationTaskIdGet(), then read getAudioSeparationRunInfoAudioSeparationResultRunIdGet().
Text-to-Voice generates a new voice from a written description. CambAIClient exposes textToVoice. Poll until TaskStatus::SUCCESS, then inspect previews from getTextToVoiceResultTextToVoiceResultRunIdGet().
<?phprequire_once __DIR__ . '/vendor/autoload.php';use Camb\Ai\CambAIClient;use Camb\Ai\Model\CreateTextToVoiceRequestPayload;use Camb\Ai\Model\TaskStatus;$client = new CambAIClient(getenv('CAMB_API_KEY'));$payload = new CreateTextToVoiceRequestPayload();$payload->setText('A confident narrator introducing a documentary.');$payload->setVoiceDescription('Deep, measured baritone with a slight gravel. Calm and authoritative.');$queued = $client->textToVoice->createTextToVoiceTextToVoicePost($payload);$taskId = $queued->getTaskId();while (true) { sleep(2); $status = $client->textToVoice->getTextToVoiceStatusTextToVoiceTaskIdGet($taskId); if ($status->getStatus() === TaskStatus::SUCCESS) { $runId = $status->getRunId(); $voiceResult = $client->textToVoice->getTextToVoiceResultTextToVoiceResultRunIdGet($runId); break; } if ($status->getStatus() === TaskStatus::ERROR) { break; }}
Preview URLs let you audition variations. Use the voice ID you choose with streaming TTS when you move to production.
Text-to-Audio turns a descriptive prompt into sound effects or ambience. Use textToAudio on the client, poll status, then stream the WAV result to disk.
<?phprequire_once __DIR__ . '/vendor/autoload.php';use Camb\Ai\CambAIClient;use Camb\Ai\Model\CreateTextToAudioRequestPayload;use Camb\Ai\Model\TaskStatus;use Camb\Ai\Model\TextToAudioType;$client = new CambAIClient(getenv('CAMB_API_KEY'));$payload = new CreateTextToAudioRequestPayload();$payload->setPrompt('Heavy rain on a tin roof at night with distant thunder.');$payload->setDuration(15.0);$payload->setAudioType(TextToAudioType::SOUND);$queued = $client->textToAudio->createTextToAudioTextToSoundPost($payload);$taskId = $queued->getTaskId();while (true) { sleep(2); $status = $client->textToAudio->getTextToAudioStatusTextToSoundTaskIdGet($taskId); if ($status->getStatus() === TaskStatus::SUCCESS) { $runId = $status->getRunId(); $audioStream = $client->textToAudio->getTextToAudioResultTextToSoundResultRunIdGet($runId); $out = fopen('soundscape.wav', 'w'); while (!$audioStream->eof()) { fwrite($out, $audioStream->fread(8192)); } fclose($out); break; } if ($status->getStatus() === TaskStatus::ERROR) { break; }}
The Stories API ingests a document, builds narration, and returns audio output. Use StoryApi with createStoryStoryPost(), poll getStoryStatusStoryTaskIdGet(), then load getStoryRunInfoStoryResultRunIdGet().
Translated TTS runs translation and synthesis together. Use TranslatedTTSApi, poll getTranslatedTtsTaskStatusTranslatedTtsTaskIdGet(), and inspect the orchestrator payload when the job succeeds.
<?phprequire_once __DIR__ . '/vendor/autoload.php';use Camb\Ai\Api\TranslatedTTSApi;use Camb\Ai\Configuration;use Camb\Ai\Model\CreateTranslatedTTSRequestPayload;use Camb\Ai\Model\Languages;use Camb\Ai\Model\TaskStatus;use GuzzleHttp\Client;$config = Configuration::getDefaultConfiguration()->setApiKey('x-api-key', getenv('CAMB_API_KEY'));$httpClient = new Client(['timeout' => 300.0]);$ttsApi = new TranslatedTTSApi($httpClient, $config);$payload = new CreateTranslatedTTSRequestPayload();$payload->setText('Good morning, welcome to our service.');$payload->setVoiceId(147320);$payload->setSourceLanguage(Languages::EN_US);$payload->setTargetLanguage(Languages::HI_IN);$queued = $ttsApi->createTranslatedTtsTranslatedTtsPost($payload);$taskId = $queued->getTaskId();while (true) { sleep(3); $status = $ttsApi->getTranslatedTtsTaskStatusTranslatedTtsTaskIdGet($taskId); if ($status->getStatus() === TaskStatus::SUCCESS) { break; } if ($status->getStatus() === TaskStatus::ERROR) { break; }}
TermTranslationInput pairs localized text with a Languages value. Build AddDictionaryTermPayload and call addTermToDictionaryDictionariesDictionaryIdAddTermPost().
<?phprequire_once __DIR__ . '/vendor/autoload.php';use Camb\Ai\Api\DictionariesApi;use Camb\Ai\Configuration;use Camb\Ai\Model\AddDictionaryTermPayload;use Camb\Ai\Model\Languages;use Camb\Ai\Model\TermTranslationInput;use GuzzleHttp\Client;$config = Configuration::getDefaultConfiguration()->setApiKey('x-api-key', getenv('CAMB_API_KEY'));$httpClient = new Client(['timeout' => 300.0]);$dictApi = new DictionariesApi($httpClient, $config);$termInput = new TermTranslationInput();$termInput->setTranslation('ā¤āĨā¤ŽāĨā¤Ŧ.ā¤ā¤ā¤');$termInput->setLanguage(Languages::HI_IN);$payload = new AddDictionaryTermPayload();$payload->setTranslations([$termInput]);$dictionaryId = 123;$dictApi->addTermToDictionaryDictionariesDictionaryIdAddTermPost($dictionaryId, $payload);$dictApi->deleteDictionaryTermDictionariesTermDictionaryIdTermIdDelete($dictionaryId, 'term_456');$dictApi->deleteDictionaryDictionariesDictionaryIdDelete($dictionaryId);
If you self-host MARS on Baseten or another backend, implement TtsProviderInterface and register it with setTtsProvider(). See Custom Cloud Providers for deployment details.