Migrating Speech-to-Text from ElevenLabs to Sarvam
Migrating Speech-to-Text from ElevenLabs to Sarvam
This guide covers migrating ElevenLabs speech-to-text (transcription) API calls to Sarvam. If you’re building a full voice agent rather than transcribing audio directly, start from the LiveKit or Pipecat voice agent build guides instead: they aren’t a 1:1 API swap and aren’t covered here.
In short: swap model_id for model, upload the audio file directly instead of passing a source_url, and pick the right Sarvam API for the job: REST for short synchronous requests, Batch for long-form or multi-speaker audio, and WebSocket for real-time streaming.
Quick start
Base URL and auth header change the same way for every ElevenLabs migration, so they’re folded in here rather than in a separate page:
With that, replace the synchronous transcription call:
Before (ElevenLabs)
After (Sarvam)
with_diarization and num_speakers are Batch API parameters. For a request like this one under 30 seconds, use the REST call above; for diarized or longer audio, use the Batch workflow below.
The rest of this page covers the full endpoint and parameter mapping, diarization via the Batch API, streaming, and common mistakes.
Endpoint map
The tables below aren’t a checklist to apply field-by-field: Quick Start above already shows the whole call swapped over in one go. Use these tables as a reference for what changed and why, not as a sequence of edits to make yourself.
Parameter concept map
Sarvam’s Batch API returns timestamps per chunk (sentence or phrase segment), which is precise enough for subtitle alignment and audio navigation. If your ElevenLabs integration reads individual words[].start/end for word-by-word highlighting, adjust it to work at the chunk level instead.
Diarization and long-form audio
ElevenLabs’ /v1/speech-to-text has no separate mode for this; Sarvam’s Batch API handles both:
See the Batch API guide for webhook setup and its Speaker Diarization section for the current per-job speaker limit.
Streaming
What’s different by design
- One current model, not a version matrix. ElevenLabs’
scribe_v1,scribe_v2, andscribe_v2_realtimebecome a singlesaaras:v3, used the same way across REST, Batch, and Streaming. - Direct file upload, no third-party fetch. Sarvam transcribes the file you send it. Download the source once (from a URL, cloud storage, or elsewhere) and upload it directly, so every request starts from the same predictable input.
- Diarization and long-form audio share one workflow. The Batch API handles speaker diarization, files up to 2 hours, and multiple files per job in a single job-based flow, using the same
with_diarization/num_speakersparameters whether the request is a short call or a large batch. - A consistent response shape. Whether diarization is on or off, Sarvam always returns the same
transcript(plusdiarized_transcriptwhen enabled), rather than switching structure based on a multichannel or output-style flag. - Indian language depth is Sarvam’s specific strength. Saaras v3 covers 22 Indian languages, including Assamese, Konkani, Kashmiri, Sindhi, Sanskrit, Santali, Manipuri, Bodo, Maithili, and Dogri, with dedicated
verbatim,translit, andcodemixoutput modes for code-mixed speech like Hinglish.
Full example
A small wrapper function, before and after, showing the complete set of changes together:
Before (ElevenLabs)
After (Sarvam)
Common mistakes
Passing a URL instead of a file
Sarvam’s file parameter expects an open file object or byte stream, not a URL string. If your ElevenLabs code used source_url to pull audio from a hosted link, download it once and upload the local file instead.
Expecting diarization on the REST endpoint
with_diarization is a Batch API parameter, not something the synchronous REST endpoint accepts. If you need diarized output, send the request through the Batch workflow, even for a short file.
Reading Batch timestamps as word-level
Batch API timestamps cover sentence or phrase chunks, not individual words. If your ElevenLabs integration builds word-by-word highlighting from words[].start/end, adjust it to highlight at the chunk level instead.
Sending Batch parameters as top-level fields
Calling the Batch endpoints directly over HTTP (rather than through the SDK) requires nesting parameters under job_parameters, e.g. {"job_parameters": {"model": "saaras:v3", ...}}. A flat body modeled on ElevenLabs’ request shape won’t be picked up.
Looking for a scribe_v1-vs-v2 equivalent
There’s only one current-generation model, saaras:v3, across every endpoint. Older saarika/saaras:v2.5 model names you’ll see elsewhere in Sarvam’s docs are legacy and being phased out, not a version choice to replicate.
See also
- Migration overview: base URL, auth, and SDK client changes
- Which Speech-to-Text API to Use
- Batch API
- Streaming API
- Speaker Diarization
- Errors & Troubleshooting