Switching STT APIs in under 30 minutes
Changing speech-to-text providers sounds risky. It isn't — if you do it behind an interface, compare on your own audio, and roll out gradually with a fallback. This is the provider-agnostic playbook; the per-provider guides (Deepgram, AssemblyAI, OpenAI Whisper, ElevenLabs, self-hosted Whisper) fill in the exact field mappings.
1. Why teams switch
- Accuracy on their audio — general WER hides how a model does on your domain, accents, and multi-speaker recordings.
- Diarization & timestamps — the difference between "a transcript" and a usable, speaker-labeled, seekable one.
- Price at volume, output formats (SRT/VTT/DOCX), and operational simplicity (no GPUs to babysit).
2. What to evaluate
| Dimension | How to judge it |
|---|---|
| Accuracy | WER on a sample of your own audio, not a vendor's demo clip |
| Diarization | DER + does the speaker labeling actually hold up on your meetings |
| Timestamps | Word-level start/end accuracy (matters for subtitles & search) |
| Languages | The specific languages and code-switching you serve |
| Formats & features | JSON shape, SRT/VTT/DOCX, custom vocabulary, webhooks |
| Throughput & price | Batch latency and cost at your monthly volume |
Measure on your data
Our public benchmark suite is reproducible and provider-agnostic — point it at your own audio and the providers you're comparing. The most honest benchmark is always yours.
3. Migrate behind an interface
Don't sprinkle vendor SDK calls across your codebase. Put transcription behind one function that returns your own normalized shape. Swapping providers then touches exactly one file. The Speech Revolutions result object is already transcript-first (.text, .words, .utterances) and can emit a Deepgram-shaped dict via to_deepgram() if you're mid-migration.
# transcription.py — the ONE place your app calls
from speechrevolutions import SpeechRevolutions
_client = SpeechRevolutions() # SPEECHREVOLUTIONS_API_KEY
def transcribe(audio: str) -> dict:
r = _client.transcribe(audio, speaker_labels=True, word_timestamps=True)
return {
"text": r.text,
"speakers": [{"speaker": u.speaker, "text": u.text} for u in r.utterances],
"words": [w.to_dict() for w in r.words],
}4. Compare outputs before you cut over
Run both providers over the same sample set through your interface, store both outputs, and diff them: WER against a reference if you have one, otherwise spot-check the transcripts, speaker turns, and timestamps that matter to your product. Keep the sample around as a regression set.
5. Roll out incrementally
- Shadow — send a copy of production traffic to Speech Revolutions, compare, don't serve it yet.
- Ramp — route 5% → 25% → 100% behind a feature flag, watching your quality and error metrics at each step.
- Fall back — on error or timeout, have the interface fall back to the old provider until you're fully confident. One interface makes this a few lines.
For large backfills
Re-transcribing an existing library? Use submit() + polling or webhooks instead of blocking calls — see the batch tutorial.
6. The 30-minute quickstart
Authenticate, transcribe, read the result — that's the whole loop.
pip install speechrevolutions
export SPEECHREVOLUTIONS_API_KEY=stt_...from speechrevolutions import SpeechRevolutions
client = SpeechRevolutions()
result = client.transcribe("meeting.mp3", speaker_labels=True)
print(result.text)Next: pick your provider-specific guide for exact field mappings, or the Quickstart to go deeper.