Deepgram-compatible API
Switch from Deepgram
A client written for Deepgram’s live transcription API connects to .wave by changing its base URL and its key. The messages it reads are the same. This page shows the change for each client, and lists what carries over and what does not.
The change
- Base URL
api.deepgram.combecomesapi.dotwave.ai. The path stays/v1/listen.- Key
- Your .wave API key, sent as before:
Authorization: Token <API key>. - Model
nemotron-asr-streaming, or leave your plugin’s default: themodelparameter is accepted as long as it is not empty.- End of speech
- Keep sending
Finalizewhen your voice detection ends a turn, or setutterance_end_ms. Deepgram’s acousticendpointinghas no equivalent here. See what changes.
Price
| Streaming transcription | Price per minute | Billed |
|---|---|---|
| .wave, Nemotron 3.5 ASR Streaming 0.6B | $0.00045 | Per minute of session, from the first audio until it closes |
| Deepgram Nova-3, monolingual, pay as you go | $0.0048 Promotional rate; $0.0077 listed as the regular rate | Per second of audio |
| Deepgram Nova-3, multilingual, pay as you go | $0.0058 Promotional rate; $0.0092 listed as the regular rate | Per second of audio |
Deepgram’s rates are read from deepgram.com/pricing on 10 October 2026 and may have changed since. .wave’s rate and credits are on Pricing and limits.
Deepgram Python SDK
With deepgram-sdk 5 and later, the client takes an environment that names the servers. Give it .wave’s, and the rest of the program stays as it is.
import os
from deepgram import DeepgramClient, DeepgramClientEnvironment
from deepgram.core.events import EventType
WAVE = DeepgramClientEnvironment(
base="https://api.dotwave.ai",
production="wss://api.dotwave.ai",
agent="wss://api.dotwave.ai", # unused: .wave has no agent API
agent_rest="https://api.dotwave.ai",
)
client = DeepgramClient(api_key=os.environ["DOTWAVE_API_KEY"], environment=WAVE)
with client.listen.v1.connect(
model="nemotron-asr-streaming",
language="pt-BR", # leave it out to detect the language
encoding="linear16",
sample_rate="16000",
interim_results="true",
) as connection:
def on_message(message):
if message.type == "Results" and message.is_final:
print(message.channel.alternatives[0].transcript)
connection.on(EventType.MESSAGE, on_message)
# Send 16 kHz mono PCM16 at the speed of speech with connection.send_media(chunk),
# connection.send_finalize() at the end of each turn, and
# connection.send_close_stream() to end the session.
connection.start_listening()With deepgram-sdk 3 and 4, pass DeepgramClientOptions(url="api.dotwave.ai") to DeepgramClient instead.
Deepgram JavaScript SDK
With @deepgram/sdk 5 and later, baseUrl is the root the SDK joins /v1/listen to.
import { DeepgramClient } from "@deepgram/sdk";
const client = new DeepgramClient({
apiKey: process.env.DOTWAVE_API_KEY,
baseUrl: "wss://api.dotwave.ai",
});
const connection = await client.listen.v1.connect({
model: "nemotron-asr-streaming",
language: "pt-BR", // leave it out to detect the language
encoding: "linear16",
sample_rate: "16000",
interim_results: "true",
});
connection.on("message", (message) => {
if (message.type === "Results" && message.is_final) {
console.log(message.channel.alternatives[0].transcript);
}
});
connection.connect();
await connection.waitForOpen();
// connection.sendMedia(chunk) at the speed of speech,
// connection.sendFinalize({ type: "Finalize" }) at the end of each turn,
// connection.sendCloseStream({ type: "CloseStream" }) to end the session.With @deepgram/sdk 3 and 4, set global.websocket.options.url to wss://api.dotwave.ai in the options of createClient.
LiveKit Agents
The Deepgram plugin takes a base URL. Keep endpointing_ms=0, since enabled endpointing is refused here, and let the agent’s own turn detection send Finalize.
import os
from livekit.plugins import deepgram
stt = deepgram.STT(
api_key=os.environ["DOTWAVE_API_KEY"],
base_url="https://api.dotwave.ai/v1/listen",
model="nemotron-asr-streaming",
language="pt-BR",
endpointing_ms=0,
)Pipecat
The Deepgram service takes a bare host as its base URL. The pipeline’s voice detection sends Finalize at the end of each turn, as it does with Deepgram. For a new pipeline, the pipecat-dotwave service on the plugins page is the shorter path.
import os
from pipecat.services.deepgram.stt import DeepgramSTTService
from pipecat.transcriptions.language import Language
stt = DeepgramSTTService(
api_key=os.environ["DOTWAVE_API_KEY"],
base_url="api.dotwave.ai",
settings=DeepgramSTTService.Settings(
model="nemotron-asr-streaming",
language=Language.PT_BR,
),
)Vapi
Vapi’s transcriber catalog has no .wave entry yet. Its custom transcriber interface sends the call’s audio to a WebSocket server you host; a small open-source server forwards each channel to .wave and returns the transcripts in Vapi’s shape. Run it where Vapi can reach it, then point the assistant at it.
{
"transcriber": {
"provider": "custom-transcriber",
"server": {
"url": "wss://transcriber.example.com/api/custom-transcriber",
"credentialId": "cred_…"
}
}
}A plain WebSocket
Without an SDK, only the host changes.
- Connect
wss://api.dotwave.ai/v1/listen?encoding=linear16&sample_rate=16000&language=pt-BR&interim_results=true- Header
Authorization: Token <API key>
The Deepgram-compatible API page has a complete example in Python.
What carries over
| Deepgram | On .wave |
|---|---|
Authorization: Token | The same header, with your .wave API key. |
Metadata, Results, SpeechStarted, UtteranceEnd | The same messages, in the same shapes. See Messages. |
is_final, speech_final, from_finalize | The same meaning: a final holds the words since the previous final; speech_final ends a segment. |
words[] with word, punctuated_word, start, end | The same fields. confidence is always 1.0. |
Finalize, CloseStream, KeepAlive | Accepted. Finalize answers with a final marked from_finalize. |
encoding=linear16, mulaw, alaw | Accepted: PCM16 at 16 or 24 kHz, G.711 at 8 kHz. See Parameters. |
language, language=multi | Accepted, with the tags on the language list. multi, or no language, detects the language. |
interim_results, utterance_end_ms | Accepted. utterance_end_ms takes 1000 to 3200. |
punctuate, smart_format, model | Accepted, so plugins keep their defaults. The model punctuates and capitalises on its own. |
What changes
| Deepgram | On .wave |
|---|---|
endpointing | Acoustic end of speech is not detected. endpointing=false is accepted; an enabled value is refused by name. Send Finalize from your own voice detection, or set utterance_end_ms, which ends a segment on the pause between recognised words. |
diarize, multichannel, keywords, keyterm | Refused, with an error that names the parameter. Send one channel; split stereo audio into two sessions. |
channels=2 | Audio must have one channel. |
| Pre-recorded transcription over HTTP | Not offered. Stream a file at the speed of speech over the same socket. |
| Audio sent faster than real time | The server holds up to 640 ms ahead of real time; past that the session closes with code 1013. Pace recorded audio. |
| Quiet sessions | A session closes after 30 seconds without audio. KeepAlive does not extend it; send silence instead. |
| Interim results that revise earlier words | Text arrives as whole words that do not change. An interim is the segment so far; a final holds the words since the previous final. |
Word confidence | Always 1.0: the model does not score its words. |
| HTTP 401, 429 on connect | The socket opens, then closes with 4401 for a bad credential or 4429 when there is no capacity. See the close codes under Messages. |
Before you switch production traffic
- Transcribe your own audio
- Run a sample of your calls through both and compare the transcripts yourself; accuracy depends on the language, the microphone and the vocabulary.
- Check your end-of-turn path
- If you relied on
endpointing, make sure your client sendsFinalizeor thatutterance_end_msis set, or finals arrive only when the socket closes. - Handle refusals and close codes
- Remove
diarize,multichannelandkeywordsfrom the query, and retry on 4429 and 4413 after a short wait. - Mind the concurrency limit
- Each project has a limit on concurrent sessions. Read it with
GET /v1/projectand write to info@dotwave.ai to raise it before you move traffic.