Other clients

Deepgram API drop-in

Deepgram's own speak APIs, Aura and Flux, through the cache: keep the Deepgram SDK, change the base URL and key.

Deepgram's Python SDK#

Deepgram’s speak APIs, mirrored under https://api.ttscacherouter.dev/deepgram: /v1/speak (Aura) and /v2/speak (Flux), REST and WebSocket. Keep the Deepgram SDK: give it the router as its environment and your router API key as its api_key.

speak.py
import asyncioimport osfrom deepgram import AsyncDeepgramClientfrom deepgram.environment import DeepgramClientEnvironmentasync def main():    client = AsyncDeepgramClient(        api_key=os.environ["TTS_CACHE_ROUTER_API_KEY"],        environment=DeepgramClientEnvironment(            base="https://api.ttscacherouter.dev/deepgram",            production="wss://api.ttscacherouter.dev/deepgram",            agent="wss://agent.deepgram.com",            agent_rest="https://agent.deepgram.com",        ),    )    with open("speech.mp3", "wb") as f:        async for chunk in client.speak.v1.audio.generate(            text="Your order has shipped. It arrives on Friday.",            model="aura-2-thalia-en",        ):            f.write(chunk)asyncio.run(main())

speak.v1 and speak.v2, REST (audio.generate) and WebSocket (connect), work through the router with every model, voice, encoding and setting. Requests are forwarded as you sent them, with the Deepgram key stored under Provider keys; your key goes in Authorization: Token, as Deepgram’s does. For a LiveKit agent, see Deepgram with LiveKit.

REST#

  • POST /deepgram/v1/speak: Aura. The audio in the encoding and container the query asks for, with Deepgram’s own Content-Type.
  • POST /deepgram/v2/speak: Flux, batch.

Any other path under /deepgram answers 404.

curl -N "https://api.ttscacherouter.dev/deepgram/v1/speak?model=aura-2-thalia-en&encoding=linear16&container=none&sample_rate=24000" \  -H "Authorization: Token $TTS_CACHE_ROUTER_API_KEY" \  -H "Content-Type: application/json" \  -d '{"text": "Your order has shipped."}' \  --output speech.pcm

WebSocket#

  • wss://api.ttscacherouter.dev/deepgram/v1/speak: Aura’s streaming API. Send Speak text and Flush; you get the audio as binary messages, Flushed after each flush’s audio, Cleared after Clear.
  • wss://api.ttscacherouter.dev/deepgram/v2/speak: Flux. Each turn (the text up to a Flush) gets SpeechStarted, its audio, Flushed and SpeechMetadata; Interrupt, Configure and Close work as at Deepgram.

The router splits your text into sentences and serves each sentence from the cache or synthesizes it at Deepgram, so the messages are Deepgram’s with these differences:

  • Audio for a sentence starts once the sentence is complete. Deepgram’s Aura starts at a comma.
  • Aura’s opening Metadata and Flux’s Connected carry the router’s own request and model ids, and model_version is unknown: no Deepgram request exists yet when you connect. A Flux turn’s speech_id is the router’s own too.
  • A Flux turn’s SpeechMetadata covers the whole turn. billable_character_count counts only the sentences Deepgram synthesized: sentences served from the cache cost nothing at Deepgram.
  • SpeechInterrupted splits the turn’s text into text_spoken and text_remaining at sentence boundaries: a sentence whose audio had started playing at playback_offset counts as spoken.
  • Configure applies to the sentences after it.
  • Aura’s limit of 20 flushes a minute doesn’t apply.
  • A failure at Deepgram (a wrong voice, your Deepgram quota) arrives as an Error message once a sentence needs Deepgram, then the router closes the connection (code 1011). A connection idle for 30 minutes is closed.

What is cached#

  • REST: each request as a whole. The same query and text again replays the same audio.
  • WebSocket: each sentence, so a sentence you have sent before with the same settings comes from the cache whatever came around it. Aura’s sentences share the cache with the router’s own /v1/stream and REST requests with the same settings.
  • A reply from the cache carries only Content-Type: no Deepgram request produced it, so there are no dg-* headers.
  • Aura: the first sentence of a reply after a pause of about five seconds or more takes about 0.7–1.2 s longer to start than Deepgram’s own WebSocket, because Deepgram closes idle connections and the router opens a new one. Sentences from the cache, and Flux, start as fast as ever.

Errors#

A wrong or missing router key gets Deepgram’s own refusal, HTTP 401, on REST and at the WebSocket handshake. So does an org with no Deepgram key stored, with a message that links to the dashboard. Errors from Deepgram, such as a model your Deepgram project can’t use, reach you as Deepgram sent them.

HTTP/1.1 401 Unauthorized{"err_code": "INVALID_AUTH", "err_msg": "Invalid credentials.", "request_id": null}