Other clients
/v1/audio/speech
Speech over HTTP, shaped like OpenAI's audio/speech: the OpenAI SDK works with the base URL and key changed.
Request#
POST https://api.ttscacherouter.dev/v1/audio/speech with your router API key as Authorization: Bearer tcr_…. The router splits input into sentences, serves each one your org has synthesized before from the cache, and synthesizes the rest with the provider key stored for your org. Audio streams back as each sentence is ready.
import osfrom openai import OpenAIclient = OpenAI( base_url="https://api.ttscacherouter.dev/v1", api_key=os.environ["TTS_CACHE_ROUTER_API_KEY"],)with client.audio.speech.with_streaming_response.create( model="sarvam/bulbul:v3", voice="shubh", input="नमस्ते, मैं सिटी हॉस्पिटल से प्रिया बोल रही हूँ।", response_format="mp3", extra_body={"language": "hi-IN"},) as response: response.stream_to_file("speech.mp3")curl https://api.ttscacherouter.dev/v1/audio/speech \ -H "Authorization: Bearer $TTS_CACHE_ROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "raya/standard", "voice": "d6a002d0-230c-49b1-a137-b8a7d564b1ae", "language": "hi", "input": "नमस्ते, मैं प्रिया बोल रही हूँ।", "response_format": "wav"}' \ --output speech.wav# client: as in the OpenAI SDK tabwith client.audio.speech.with_streaming_response.create( model="elevenlabs/eleven_flash_v2_5", voice="JBFqnCBsd6RMkjVDRZzb", input="Your order has shipped. It arrives on Friday.", response_format="mp3", extra_body={ "sample_rate": 22050, "voice_settings": {"stability": 0.5, "similarity_boost": 0.75, "speed": 1.1}, },) as response: response.stream_to_file("speech.mp3")Provider-specific fields go in the body; with the OpenAI SDK, pass them in extra_body.
Body#
modelstringRequired<provider>/<model>:sarvam/bulbul:v3,sarvam/bulbul:v4-flash,raya/standard,raya/m1, or an ElevenLabs model such aselevenlabs/eleven_flash_v2_5(see Models and options).inputstringRequired- The text to speak, up to 20,000 characters.
voicestringRequired- A Sarvam speaker, a Raya voice id or an ElevenLabs voice id, belonging to the model. See Models and options.
languagestringRequired; optional for ElevenLabs- The provider’s language code:
hi-INfor Sarvam,hifor Raya,enfor ElevenLabs (which detects the language when it is left out). response_formatstringDefault"mp3"- See Formats.
speednumberDefault1.0- Sarvam 0.5–2.0, Raya 0.5–1.5. Refused for ElevenLabs: use
voice_settings.speed. sample_rateintegerDefault240008000,16000,22050or24000; Sarvam also32000,44100or48000, where each sentence arrives only once it is fully synthesized andbitrateis fixed at128k. ElevenLabs:8000–48000forpcmandwav;mulawandalawdefault to their only rate,8000.temperaturenumberSarvam only- 0.01–1.0, default 0.6.
dict_idstringSarvam only- A Sarvam pronunciation dictionary to apply.
pitchnumberSarvam bulbul:v4-flash only- -0.5 (deeper) to 0.5 (higher), default 0.
loudnessnumberSarvam bulbul:v4-flash only- 0.1–2.5, default 1.0.
enable_preprocessingbooleanSarvam bulbul:v4-flash only- Normalize numbers and English words in the text before synthesis. Default
false. bitratestringSarvam, ElevenLabs- Sarvam, for
mp3andaac:32k,64k,96k,128kor192k, default128k. ElevenLabs, formp3:32kat 22050 Hz,48kat 24000 Hz,32k–192kat 44100 Hz (default128k). voice_settingsobject | nullElevenLabs onlystabilityandsimilarity_boost(0–1, both required), and optionallystyle(0–1),speed(0.7–1.2) anduse_speaker_boost. Null: the voice’s stored settings.apply_text_normalizationstringElevenLabs onlyauto(default),onoroff.apply_language_text_normalizationbooleanElevenLabs only- Language-specific normalization (Japanese).
enable_ssml_parsingbooleanElevenLabs only- Parse SSML tags. Default
false. enable_loggingbooleanElevenLabs onlyfalsefor ElevenLabs’ zero-retention mode (enterprise accounts). Defaulttrue.pronunciation_dictionary_locatorsarrayElevenLabs only- Up to 3
{pronunciation_dictionary_id, version_id}. stream_format"audio"Default"audio"- The body is the audio itself.
sseis not supported.
Any other field, such as OpenAI’s instructions, is a bad_request.
Formats#
Every format is produced by the provider itself; the router never re-encodes audio. Only formats whose sentences join into one valid stream are offered.
| response_format | Sarvam | Raya | ElevenLabs |
|---|---|---|---|
| pcm | Yes | Yes | Yes |
| wav | Yes | Yes | Yes |
| mp3 | Yes | No | 22050, 24000, 44100 Hz |
| aac | Yes | No | No |
| mulaw | Yes | Yes | 8000 Hz |
| alaw | Yes | No | 8000 Hz |
| flac, opus | No | No | No |
pcmis raw 16-bit little-endian mono atsample_rate;wavis the same with a WAV header for streaming (its size fields are left open).mulawandalaware 8-bit G.711 atsample_rate, for telephony.- Any other combination is refused with HTTP 400.
Content types: audio/pcm, audio/wav, audio/mpeg, audio/aac, audio/mulaw, audio/alaw.
Errors#
An error before any audio is a JSON body with an HTTP status. The codes are the WebSocket protocol's.
{ "error": { "code": "provider_rejected", "message": "…", "retryable": false, "provider_status": 403 }}bad_requestHTTP 400, not retryable- The request failed validation or a message arrived out of order. The message says which field or rule.
unauthorizedHTTP 401, not retryable- The API key is missing, wrong or deleted, or its org is disabled.
insufficient_creditsHTTP 402, not retryable- Your org is out of credit, so the router refuses new connections and requests until you buy more. Connections already open carry on.
provider_key_missingHTTP 400, not retryable- Your org has no key stored for the provider. Add one under Provider keys.
provider_rejectedHTTP 400, not retryable- The provider refused the request, e.g. a wrong stored provider key or an unknown voice. The provider’s message is passed through.
provider_rate_limitedHTTP 429, retryable- Your own quota at the provider is exhausted.
provider_unavailableHTTP 502, retryable- The provider returned a server error, or the connection to it failed or closed unexpectedly.
provider_timeoutHTTP 504, retryable- The provider took too long to send audio.
internalHTTP 500, retryable- The router failed.