Migrating from Deepgram to Speech Revolutions

Deepgram's pre-recorded API is a single synchronous POST: you send raw audio bytes to /v1/listen and get the full transcript back in one response. Speech Revolutions uses an upload-then-wait flow, and the SDK wraps it in one transcribe() call, so most of the migration is renaming. This guide maps each part of the API, including the to_deepgram() helper, which returns Deepgram-shaped JSON so your existing response parsing keeps working.

The one-line version

Speech Revolutions accepts Deepgram's diarize=true as an alias for speaker_labels. result.to_deepgram() returns the output in the results.channels[0].alternatives[0] structure you already parse.

Authentication

Deepgram authenticates with an Authorization: Token <key> header. Speech Revolutions uses an X-API-Key header. The SDKs read the key from the environment.

DeepgramSpeech Revolutions
Authorization: Token DEEPGRAM_API_KEYX-API-Key: SPEECHREVOLUTIONS_API_KEY
DEEPGRAM_API_KEY env varSPEECHREVOLUTIONS_API_KEY
bash
# was
export DEEPGRAM_API_KEY=...
# now
export SPEECHREVOLUTIONS_API_KEY=stt_...

Endpoint & method mapping

Deepgram uses one synchronous endpoint. Speech Revolutions separates job creation and retrieval. The SDK's transcribe() runs the whole flow and blocks until the transcript is ready, which is the closest equivalent to a single Deepgram call.

DeepgramSpeech Revolutions RESTSpeech Revolutions SDK
POST /v1/listen (sync)POST /api/v1/transcribe (raw bytes in, transcript streamed back; up to 200 MB)transcribe() (blocks) or submit() (non-blocking)
— (response is inline)GET /api/v1/jobs/{id}/stream (SSE progress)on_progress callback
— (response is inline)GET /api/v1/jobs/{id}get_job_status() / get_transcript()

Upload differences

Deepgram takes raw audio bytes directly in the request body with a Content-Type that matches the file. With Speech Revolutions, you pass a path, URL, bytes, or file object to the SDK's transcribe(), which uploads large files to object storage in parts. Speech Revolutions also reports upload and transcribe progress; Deepgram exposes no percentage for pre-recorded audio.

Response shape

Deepgram nests everything under results.channels[0].alternatives[0], with word-level speakers as integers. Speech Revolutions returns a flat transcript object. The fields map as follows:

Deepgram fieldSpeech Revolutions
...alternatives[0].transcriptresult.text (or result.transcript)
...alternatives[0].words[] (word, start, end)result.words (text, start, end)
per-word speaker (integer, e.g. 0)per-word speaker (string, e.g. SPEAKER_1) plus result.utterances (grouped speaker turns)
results.channels[0].detected_languageresult.languages
the whole Deepgram JSONresult.to_deepgram() reproduces it

If your code already reads results.channels[0].alternatives[0], call result.to_deepgram() and pass the result to your existing code unchanged.

python
dg = result.to_deepgram()
print(dg["results"]["channels"][0]["alternatives"][0]["transcript"])

Diarization

Deepgram diarizes with diarize=true, tagging each word with an integer speaker. Speech Revolutions accepts the same diarize flag (an alias for speaker_labels) and also groups words into result.utterances, so you don't need to rebuild speaker turns from per-word labels. Zephyr ranks #1 on diarization error rate on every benchmark subset. See the benchmarks and the comparison table.

Timestamps

Both return per-word start and end times in seconds. Speech Revolutions enables word timestamps by default (word_timestamps=true) and returns them on result.words.

Language selection

Deepgram takes a BCP-47 language query param, or detect_language=true to auto-detect. Speech Revolutions auto-detects by default, so remove detect_language from your request. Detection runs per segment, not per request: result.languages returns language spans, so a bilingual recording is labeled with both languages. To set a fixed language, pass language with an ISO 639-1 code, so en-US becomes en. This skips detection for the whole file; see pinning the language.

Side by side

Diarized transcription, before and after. The "before" examples use deepgram-sdk v3 for Python (v4 has the same shape), @deepgram/sdk v4 for JavaScript, deepgram-go-sdk v3 for Go, and the Deepgram 7.x package for .NET. The Python and JavaScript v5 clients are different, so if you use v5 or newer, your existing code differs from this example. The Speech Revolutions code is the same either way.

deepgram_transcribe.py

From Deepgram — Python (deepgram_transcribe.py)

from deepgram import DeepgramClient, PrerecordedOptions

dg = DeepgramClient()  # DEEPGRAM_API_KEY

with open("meeting.mp3", "rb") as f:
    source = {"buffer": f.read(), "mimetype": "audio/mp3"}

options = PrerecordedOptions(model="nova-3", diarize=True, smart_format=True)
resp = dg.listen.rest.v("1").transcribe_file(source, options)

alt = resp["results"]["channels"][0]["alternatives"][0]
print(alt["transcript"])
for w in alt["words"]:
    print(w["speaker"], w["word"], w["start"], w["end"])

Common pitfalls

  • Auth header. Use X-API-Key, not Authorization: Token. The SDK sets it for you; update any direct HTTP calls.
  • Speaker type. Speech Revolutions speakers are strings (SPEAKER_1), not integers. Use result.utterances instead of grouping words yourself, or call to_deepgram() for the integer form.
  • No inline response. Each request creates a job that you wait on. transcribe() handles this. If you call the REST API directly, follow the upload → complete → poll or stream flow.
  • Keyword biasing. Deepgram's repeatable keyterm maps to the custom_vocabulary list.

See the migration playbook for cutover, and the benchmarks for accuracy and diarization comparisons.