Integrationsvoice
Deepgram voice
Transcribe audio with Nova-3 and speak text with Aura voices through @mayurajs/voice-deepgram: prices, bounds, formats and errors.
- Package
- @mayurajs/voice-deepgram
- Install
- npm install mayura @mayurajs/voice-deepgram
- Vendor
- Deepgram ↗
Deepgram serves speech-to-text (Nova-3, Whisper) and text-to-speech (Aura-2, Aura).
@mayurajs/voice-deepgram plugs them into the voice registry, so your code and your agents use
them with the same ids, prices, per-call bounds and voice:<id> permissions as every other voice provider. It talks to
Deepgram's HTTP API with fetch: no Deepgram SDK, no other dependencies, and it runs on every runtime Mayura runs on.
Install
npm install mayura @mayurajs/voice-deepgramCredentials
Create an API key in the Deepgram console under API Keys. The package calls only
/v1/listen and /v1/speak, and sends the key as Authorization: Token <key>. The package reads nothing from the
environment: pass the key in yourself, for example from DEEPGRAM_API_KEY.
Use it
import { createVoices, transcriptionTool } from 'mayura/voice';
import { deepgramVoice } from '@mayurajs/voice-deepgram';
const voices = createVoices({
providers: [deepgramVoice({ apiKey: process.env.DEEPGRAM_API_KEY ?? '' })],
prices: 'catalog',
maxCallCostMicros: 50_000,
});
// Speech ids name a model family; the voice completes it: aura-2 with thalia-en is Deepgram's aura-2-thalia-en.
const speech = await voices.speaker('deepgram/aura-2').speak({ text: 'Your order ships tomorrow.', voice: 'thalia-en', format: 'wav' });
// WAV is measured, so no duration is needed. Without a language, Deepgram detects it.
const transcript = await voices.transcriber('deepgram/nova-3').transcribe({ audio: speech.audio });
console.log(transcript.text, transcript.language, transcript.usage.costMicros);
// A tool for agents and workflows: grant tool:voice.transcribe and voice:deepgram/nova-3 to the run.
const transcribe = transcriptionTool(voices.transcriber('deepgram/nova-3'));Ids are deepgram/<model>. Each voice tool requires voice:<id> besides tool:<tool id>, reserves the model's
per-call bound from the run's budget and reports what the call cost. See
Voice.
Options
| Option | Default | Meaning |
|---|---|---|
apiKey |
required | Your Deepgram API key. |
baseURL |
https://api.deepgram.com |
Send requests here instead, for example a self-hosted or EU endpoint. It must be https. |
headers |
none | Up to 8 extra headers, such as a gateway's credential. They cannot replace Authorization, Content-Type, Host or cookies. |
maxAudioBytes |
64 MiB | The largest speech audio a call may return. |
maxResponseBytes |
16 MiB | The largest transcription response (word timings make long audio's responses large). |
timeoutMs |
120 s | How long one call may take, unless the registry or the model sets timeoutMs. |
fetch |
globalThis.fetch |
For tests and proxies. |
Models and prices
The catalog has Deepgram's pay-as-you-go prices for pre-recorded audio as of 2026-09-30, used when you pass
prices: 'catalog':
| Id | Kind | Catalog price |
|---|---|---|
deepgram/nova-3 |
Speech-to-text | $0.0052 a minute, its multilingual rate |
deepgram/whisper-large |
Speech-to-text | $0.0048 a minute |
deepgram/aura-2 |
Text-to-speech | $30 per million characters |
deepgram/aura |
Text-to-speech | $15 per million characters |
Nova-3 costs more when it transcribes several languages than one, under the same model id, so the catalog lists it at
the multilingual rate: a catalog price may overcount, never undercount. Give your own price in prices if you know your
audio is monolingual. Another Deepgram model works with a price you give.
Cost bounds
Every call is priced before it is sent, and refused with BUDGET_EXCEEDED if it would cost more than the model's bound:
speech from its text's characters (Unicode code points), and transcription from the audio's duration, measured from WAV
or given as durationMs for compressed audio. With a 50,000-micro bound, deepgram/aura-2 speaks up to 1,666
characters a call and deepgram/nova-3 transcribes up to about 9 and a half minutes.
The cost a transcription reports is what Deepgram billed: the duration in its response's metadata, and otherwise the duration measured or given. Speech is charged for the characters of the text.
Audio and formats
- Transcription sends the audio's bytes as the request body with its media type, with smart formatting on. A
languageis sent as given (pt-BR); without one, Deepgram is asked to detect it and the transcript reports what it found. Segments are words, with their timings and a speaker when Deepgram reports one. The registry accepts up to 25 MiB of audio by default. - Speech comes in every Mayura format:
mp3(the default),opus(in Ogg,audio/ogg),aac,flac,wav(16-bit linear PCM in WAV) andpcm16(raw 16-bit PCM at 24 kHz). Audio streams toonAudioas it arrives. - The voice completes the model family: lowercase letters, optionally followed by a language such as
-en, as inthalia-en. Anything else fails withconfigurationbefore a request is made. - A speech response that is not audio, is empty, or is larger than
maxAudioBytesfails withinvalid_response, as does a transcription response larger thanmaxResponseBytes. Redirects are not followed.
Errors
Failures reach you as a VoiceProviderError with a reason. Its message is fixed text: nothing Deepgram wrote reaches
it.
reason |
When |
|---|---|
authentication |
Deepgram answered 401 or 403: the key is wrong or lacks permission. |
rate_limited |
Deepgram answered 402 or 429: a rate limit or quota was reached. |
unavailable |
Deepgram answered 408 or 5xx, or could not be reached. |
rejected |
Deepgram refused the request with another status, for example an unknown model or unreadable audio. |
timeout |
The call took longer than its timeoutMs. |
invalid_response |
The response was not what Deepgram's API promises, or was too large. |
configuration |
The voice is not a Deepgram voice name. |
A call cancelled through its signal fails with CANCELLED. Before anything is sent, the registry refuses a call over
its bound (BUDGET_EXCEEDED), audio or text over its limits (LIMIT_EXCEEDED), and compressed audio without
durationMs (INVALID_INPUT). A missing key, a non-https baseURL or a malformed model id fails with
INVALID_CONFIG.
How it is tested
- Unit tests run the package against a fake Deepgram API in Deepgram's own wire format. They check the URLs and query
parameters, the
Authorizationheader, that the raw audio is sent with its media type, language detection, the family-and-voice model name, catalog charges and refused voices, and that nothing is read from the environment. - The voice adapter conformance suite passes against that fake: result shapes, costs, HTTP failures mapped without Deepgram's text, cancellation and timeouts.
scripts/live/voice-deepgram.mjspassed against a real Deepgram account on October 6, 2026:aura-2withthalia-enspoke a sentence, andnova-3transcribed it back with its words, through the shared voice checks at catalog prices.
Related
- Voice: the registry, prices, bounds and voice tools.
- AssemblyAI transcription: another transcription provider.
- ElevenLabs voice: another provider that speaks and transcribes.
- Costs and budgets: how a run's budget reserves each call's bound.