Docs / Deepgram-compatible API / Switch from Deepgram

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.com becomes api.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: the model parameter is accepted as long as it is not empty.
End of speech
Keep sending Finalize when your voice detection ends a turn, or set utterance_end_ms. Deepgram’s acoustic endpointing has no equivalent here. See what changes.

Price

Streaming transcriptionPrice per minuteBilled
.wave, Nemotron 3.5 ASR Streaming 0.6B$0.00045Per 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 ratePer second of audio
Deepgram Nova-3, multilingual, pay as you go$0.0058 Promotional rate; $0.0092 listed as the regular ratePer 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

DeepgramOn .wave
Authorization: TokenThe same header, with your .wave API key.
Metadata, Results, SpeechStarted, UtteranceEndThe same messages, in the same shapes. See Messages.
is_final, speech_final, from_finalizeThe same meaning: a final holds the words since the previous final; speech_final ends a segment.
words[] with word, punctuated_word, start, endThe same fields. confidence is always 1.0.
Finalize, CloseStream, KeepAliveAccepted. Finalize answers with a final marked from_finalize.
encoding=linear16, mulaw, alawAccepted: PCM16 at 16 or 24 kHz, G.711 at 8 kHz. See Parameters.
language, language=multiAccepted, with the tags on the language list. multi, or no language, detects the language.
interim_results, utterance_end_msAccepted. utterance_end_ms takes 1000 to 3200.
punctuate, smart_format, modelAccepted, so plugins keep their defaults. The model punctuates and capitalises on its own.

What changes

DeepgramOn .wave
endpointingAcoustic 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, keytermRefused, with an error that names the parameter. Send one channel; split stereo audio into two sessions.
channels=2Audio must have one channel.
Pre-recorded transcription over HTTPNot offered. Stream a file at the speed of speech over the same socket.
Audio sent faster than real timeThe server holds up to 640 ms ahead of real time; past that the session closes with code 1013. Pace recorded audio.
Quiet sessionsA session closes after 30 seconds without audio. KeepAlive does not extend it; send silence instead.
Interim results that revise earlier wordsText 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 confidenceAlways 1.0: the model does not score its words.
HTTP 401, 429 on connectThe 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 sends Finalize or that utterance_end_ms is set, or finals arrive only when the socket closes.
Handle refusals and close codes
Remove diarize, multichannel and keywords from 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/project and write to info@dotwave.ai to raise it before you move traffic.