Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.camb.ai/llms.txt

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.

Installation

Requires PHP 8.1 or later and Composer. Add the Camb.ai repository and package to your composer.json:
{
  "repositories": [
    {
      "type": "vcs",
      "url": "https://github.com/Camb-ai/cambai-php-sdk.git"
    }
  ],
  "require": {
    "camb-ai/cambai-php-sdk": "*@dev"
  }
}
Then run:
composer install

Authentication

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.
<?php
require_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.

Quick Start

Streaming TTS returns a readable stream. DefaultTtsProvider::tts() maps to the streaming endpoint. Read the stream in chunks and write them to disk.
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\CambAIClient;
use Camb\Ai\Model\CreateStreamTTSRequestPayload;
use Camb\Ai\Model\StreamTTSOutputConfiguration;

$client = new CambAIClient(getenv('CAMB_API_KEY'));

$outputConfig = new StreamTTSOutputConfiguration();
$outputConfig->setFormat('wav');

$payload = new CreateStreamTTSRequestPayload();
$payload->setText('Hello from Camb.ai.');
$payload->setVoiceId(147320);
$payload->setLanguage(CreateStreamTTSRequestPayload::LANGUAGE_EN_US);
$payload->setSpeechModel(CreateStreamTTSRequestPayload::SPEECH_MODEL_MARS_FLASH);
$payload->setOutputConfiguration($outputConfig);

$audioStream = $client->tts()->tts($payload);
$outputFile = 'output.wav';
$file = fopen($outputFile, 'w');
if ($file) {
    while (!$audioStream->eof()) {
        fwrite($file, $audioStream->fread(8192));
    }
    fclose($file);
}

Non-streaming TTS

If you need a task-based TTS job instead of streaming, call createTts() on the same provider, poll task status, then fetch run metadata.
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\CambAIClient;
use Camb\Ai\Model\CreateTTSRequestPayload;
use Camb\Ai\Model\Languages;
use Camb\Ai\Model\OrchestratorPipelineResult;
use Camb\Ai\Model\TaskStatus;

$client = new CambAIClient(getenv('CAMB_API_KEY'));

$payload = new CreateTTSRequestPayload();
$payload->setText('Hello from Camb.ai.');
$payload->setVoiceId(147320);
$payload->setLanguage(Languages::EN_US);
$payload->setSpeechModel('mars-flash');

$created = $client->tts()->createTts($payload);
$taskId = $created->getTaskId();

while (true) {
    /** @var OrchestratorPipelineResult $status */
    $status = $client->textToSpeech->getTtsResultTtsTaskIdGet($taskId);
    if ($status->getStatus() === TaskStatus::SUCCESS) {
        $runId = $status->getRunId();
        $ttsRunInfo = $client->textToSpeech->getTtsRunInfoTtsResultRunIdGet($runId);
        break;
    }
    if ($status->getStatus() === TaskStatus::ERROR) {
        break;
    }
    sleep(2);
}
When the loop exits with success, $ttsRunInfo holds download URLs and metadata for the synthesized audio.

Models

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.
ModelSample RateBest For
mars-8.1-flash-beta48 kHzFaster MARS 8.1 generation; same quality improvements as mars-8.1-pro-beta
mars-8.1-pro-beta48 kHzImproved pronunciation, expressiveness, and prosody over mars-pro
mars-flash22.05 kHzLow-latency real-time applications and conversational AI
mars-pro48 kHzHigh-fidelity audio production and long-form content
mars-instruct22.05 kHzFine-grained tone and style control via text instructions
The tab snippets below reuse $client from Quick Start.
$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);
For beta models, pass the string on the payload when no constant exists:
$payload->setSpeechModel('mars-8.1-flash-beta');

Voices

VoiceCloningApi lists voices and creates custom voices. Instantiate it with $httpClient and $config from Authentication.

List voices

Call listVoicesListVoicesGet() to retrieve voices on your account. The id field is the voice_id you pass to TTS.
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\Api\VoiceCloningApi;
use Camb\Ai\Configuration;
use GuzzleHttp\Client;

$config = Configuration::getDefaultConfiguration()->setApiKey('x-api-key', getenv('CAMB_API_KEY'));
$httpClient = new Client(['timeout' => 300.0]);

$voiceApi = new VoiceCloningApi($httpClient, $config);
$voices = $voiceApi->listVoicesListVoicesGet();

foreach ($voices as $voice) {
    echo 'ID: ' . $voice->getId() . ', Name: ' . $voice->getVoiceName() . PHP_EOL;
}

Create a custom voice

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.
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\Api\VoiceCloningApi;
use Camb\Ai\Configuration;
use Camb\Ai\Model\Gender;
use Camb\Ai\Model\Languages;
use GuzzleHttp\Client;

$config = Configuration::getDefaultConfiguration()->setApiKey('x-api-key', getenv('CAMB_API_KEY'));
$httpClient = new Client(['timeout' => 300.0]);

$voiceApi = new VoiceCloningApi($httpClient, $config);
$file = new \SplFileObject(__DIR__ . '/reference.wav');

$result = $voiceApi->createCustomVoiceCreateCustomVoicePost(
    'My Custom Voice',
    Gender::NUMBER_1,
    $file,
    null,
    'Warm and conversational.',
    null,
    30,
    Languages::EN_US,
    true
);

Language Support

Camb.ai supports many languages. Prefer Languages enum values on payloads so editors catch invalid codes.
use Camb\Ai\Model\Languages;

$payload->setLanguage(Languages::EN_US);
$payload->setLanguage(Languages::FR_FR);
To fetch supported languages at runtime, use LanguagesApi with the same configuration pattern as voice cloning.
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\Api\LanguagesApi;
use Camb\Ai\Configuration;
use GuzzleHttp\Client;

$config = Configuration::getDefaultConfiguration()->setApiKey('x-api-key', getenv('CAMB_API_KEY'));
$httpClient = new Client(['timeout' => 300.0]);

$langApi = new LanguagesApi($httpClient, $config);

$sourceLanguages = $langApi->getSourceLanguagesSourceLanguagesGet();
$targetLanguages = $langApi->getTargetLanguagesTargetLanguagesGet();
Per-model language lists are documented under MARS Models.

Dubbing

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.
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\CambAIClient;
use Camb\Ai\Model\EndToEndDubbingRequestPayload;
use Camb\Ai\Model\Languages;
use Camb\Ai\Model\TaskStatus;

$client = new CambAIClient(getenv('CAMB_API_KEY'));

$payload = new EndToEndDubbingRequestPayload();
$payload->setVideoUrl('https://example.com/video.mp4');
$payload->setSourceLanguage(Languages::EN_US);
$payload->setTargetLanguages([Languages::HI_IN, Languages::FR_FR]);

$queued = $client->dub->endToEndDubbingDubPost($payload);
$taskId = $queued->getTaskId();

while (true) {
    sleep(5);
    $statusResult = $client->dub->getEndToEndDubbingStatusDubTaskIdGet($taskId);
    $status = $statusResult->getStatus();

    if ($status === TaskStatus::SUCCESS) {
        $runId = $statusResult->getRunId();
        $dubResult = $client->dub->getDubbedRunInfoDubResultRunIdGet($runId);
        $videoUrl = $dubResult->getDubbingResult()->getVideoUrl();
        break;
    }

    if ($status === TaskStatus::ERROR) {
        break;
    }
}

Get transcript

After a successful dub, fetch the transcript for a target language using getDubbedRunTranscriptTranscriptRunIdLanguageGet().
$transcript = $client->dub->getDubbedRunTranscriptTranscriptRunIdLanguageGet(
    $runId,
    Languages::HI_IN
);

Translation

Translation accepts an ordered list of strings and returns translations in the same order. Submit a job, poll getTranslationTaskStatusTranslateTaskIdGet(), then load results with getTranslationResultTranslationResultRunIdGet().
<?php
require_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().

Transcription

Send audio or video by URL or as an uploaded file. Poll getTranscriptionTaskStatusTranscribeTaskIdGet(), then call getTranscriptionResultTranscriptionResultRunIdGet() with optional word-level timestamps.
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\Api\TranscriptionApi;
use Camb\Ai\Configuration;
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]);

$transcriptionApi = new TranscriptionApi($httpClient, $config);

$queued = $transcriptionApi->createTranscriptionTranscribePost(
    Languages::EN_US,
    null,
    null,
    'https://example.com/audio.mp3'
);
$taskId = $queued->getTaskId();

while (true) {
    sleep(3);
    $status = $transcriptionApi->getTranscriptionTaskStatusTranscribeTaskIdGet($taskId);
    if ($status->getStatus() === TaskStatus::SUCCESS) {
        $runId = $status->getRunId();
        $result = $transcriptionApi->getTranscriptionResultTranscriptionResultRunIdGet($runId, true);
        break;
    }
    if ($status->getStatus() === TaskStatus::ERROR) {
        break;
    }
}
For a local file, pass SplFileObject as the file argument (fifth parameter).
$file = new \SplFileObject(__DIR__ . '/audio.mp3');
$queued = $transcriptionApi->createTranscriptionTranscribePost(
    Languages::EN_US,
    null,
    null,
    null,
    $file
);

Audio Separation

Separation splits a mixed recording into stems. Upload media with createAudioSeparationAudioSeparationPost(), poll getAudioSeparationStatusAudioSeparationTaskIdGet(), then read getAudioSeparationRunInfoAudioSeparationResultRunIdGet().
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\Api\AudioSeparationApi;
use Camb\Ai\Configuration;
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]);

$audioSeparationApi = new AudioSeparationApi($httpClient, $config);
$media = new \SplFileObject(__DIR__ . '/track.mp3');

$queued = $audioSeparationApi->createAudioSeparationAudioSeparationPost(null, null, $media);
$taskId = $queued->getTaskId();

while (true) {
    sleep(3);
    $status = $audioSeparationApi->getAudioSeparationStatusAudioSeparationTaskIdGet($taskId);
    if ($status->getStatus() === TaskStatus::SUCCESS) {
        $runId = $status->getRunId();
        $result = $audioSeparationApi->getAudioSeparationRunInfoAudioSeparationResultRunIdGet($runId);
        break;
    }
    if ($status->getStatus() === TaskStatus::ERROR) {
        break;
    }
}

Text-to-Voice

Text-to-Voice generates a new voice from a written description. CambAIClient exposes textToVoice. Poll until TaskStatus::SUCCESS, then inspect previews from getTextToVoiceResultTextToVoiceResultRunIdGet().
<?php
require_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

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.
<?php
require_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;
    }
}

Stories

The Stories API ingests a document, builds narration, and returns audio output. Use StoryApi with createStoryStoryPost(), poll getStoryStatusStoryTaskIdGet(), then load getStoryRunInfoStoryResultRunIdGet().
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\Api\StoryApi;
use Camb\Ai\Configuration;
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]);

$storyApi = new StoryApi($httpClient, $config);
$file = new \SplFileObject(__DIR__ . '/story.pdf');

$queued = $storyApi->createStoryStoryPost($file, Languages::EN_US, null, 'My Story');
$taskId = $queued->getTaskId();

while (true) {
    sleep(5);
    $status = $storyApi->getStoryStatusStoryTaskIdGet($taskId);
    if ($status->getStatus() === TaskStatus::SUCCESS) {
        $runId = $status->getRunId();
        $info = $storyApi->getStoryRunInfoStoryResultRunIdGet($runId);
        break;
    }
    if ($status->getStatus() === TaskStatus::ERROR) {
        break;
    }
}

Translated TTS

Translated TTS runs translation and synthesis together. Use TranslatedTTSApi, poll getTranslatedTtsTaskStatusTranslatedTtsTaskIdGet(), and inspect the orchestrator payload when the job succeeds.
<?php
require_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;
    }
}

Dictionaries

Dictionaries store term mappings for dubbing and translation workflows.

List dictionaries

<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\Api\DictionariesApi;
use Camb\Ai\Configuration;
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);
$dictionaries = $dictApi->getDictionariesDictionariesGet();

foreach ($dictionaries as $dictionary) {
    echo $dictionary->getId() . ': ' . $dictionary->getName() . PHP_EOL;
}

Create from file

$dictionaryFile = new \SplFileObject(__DIR__ . '/terms.csv');
$dictApi->createDictionaryFromFileDictionariesCreateFromFilePost(
    $dictionaryFile,
    'Product Terms',
    null,
    'Brand-specific terminology for our product line.'
);

Manage terms

TermTranslationInput pairs localized text with a Languages value. Build AddDictionaryTermPayload and call addTermToDictionaryDictionariesDictionaryIdAddTermPost().
<?php
require_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);

Error Handling

HTTP failures surface as ApiException. Read the status code and decoded body for debugging.
<?php
require_once __DIR__ . '/vendor/autoload.php';

use Camb\Ai\ApiException;
use Camb\Ai\CambAIClient;
use Camb\Ai\Model\CreateStreamTTSRequestPayload;

$client = new CambAIClient(getenv('CAMB_API_KEY'));

$payload = new CreateStreamTTSRequestPayload();
$payload->setText('Hello world.');
$payload->setVoiceId(147320);
$payload->setLanguage(CreateStreamTTSRequestPayload::LANGUAGE_EN_US);

try {
    $stream = $client->tts()->tts($payload);
    while (!$stream->eof()) {
        $stream->fread(8192);
    }
} catch (ApiException $e) {
    echo $e->getCode() . ': ' . $e->getMessage() . PHP_EOL;
    if ($e->getResponseBody()) {
        print_r($e->getResponseBody());
    }
}

Custom Provider

If you self-host MARS on Baseten or another backend, implement TtsProviderInterface and register it with setTtsProvider(). See Custom Cloud Providers for deployment details.

Baseten

Point the provider at your deployment URL and supply credentials from the environment.
<?php
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/BasetenTtsProvider.php';

use Camb\Ai\CambAIClient;

$client = new CambAIClient(getenv('CAMB_API_KEY'));

$basetenProvider = new BasetenTtsProvider(
    getenv('BASETEN_API_KEY'),
    getenv('BASETEN_MODEL_URL')
);
$client->setTtsProvider($basetenProvider);
Copy BasetenTtsProvider.php from the SDK examples folder into your project (next to the script or on your include path) so the require_once resolves.

Next Steps

https://mintcdn.com/cambai/2LvnefIkletroPxv/images/pipecat-orange.svg?fit=max&auto=format&n=2LvnefIkletroPxv&q=85&s=40cf8e001b8cadc8a4c3c557dea603d5

Voice Agents

Build real-time voice agents with Pipecat
https://mintcdn.com/cambai/2LvnefIkletroPxv/images/livekit-orange.svg?fit=max&auto=format&n=2LvnefIkletroPxv&q=85&s=c750fcee9b1de69e3c1d0d6ec7eb6b3f

LiveKit Integration

Create voice agents with LiveKit

API Reference

Explore the full TTS API

Voice Library

Browse available voices

Resources