Streaming
Murf Speech to Text uses a single WebSocket connection. You send audio as binary frames and control messages as JSON; the server sends back partial transcripts while the caller is speaking, and a final transcript when the turn ends.
Endpoint
model is required. Connect Finch-Indic (finch_indic_1.0) to wss://in.api.murf.ai/v1/transcription/stream-input, and Finch-Global (finch_global_1.0) to wss://us-east.api.murf.ai/v1/transcription/stream-input. The overview lists the languages each model transcribes.
Pass your API key as the api_key query parameter or api-key header. See Authentication.
Quickstart
Session lifecycle
A connection is a session. A session can contain many turns, for example one per caller utterance in a voice agent.
Partial and final transcripts
Each message carries the transcript of the current turn in transcript. The same text is also in rawEvent.transcript.
partial: the transcript of the turn so far. Eachpartialcontains the whole turn up to that point, so replace the text you are showing instead of appending to it.final: the completed transcript of the turn. Use this text as the caller’s utterance, and readrawEvent.wordsif you need word timestamps.
Ending a turn
commit_mode sets how a turn ends. It accepts vad (default) or manual. Any other value closes the connection with code 4002 and the message commit_mode must be vad or manual.
-
vad(default)The server ends each turn when the caller pauses. While the caller speaks, it sends
partialmessages. When the caller stops speaking, the server waits briefly and then sendsfinalwithrawEvent.triggerset tovad. If the caller resumes speaking during that wait, the turn continues andfinalis held until the next pause.Sending
{"type": "Finalize"}ends the current turn immediately, with trigger set to manual. -
manualUse this mode when your agent or a turn-taking model decides when the caller has finished. The server still sends partial updates, but a pause does not end the turn. Send
{"type": "Finalize"}to end it. If there was no pending speech, final is still sent with an empty transcript.
After a turn ends
Keep sending audio on the same connection. The next speech starts a new turn. rawEvent.turn_index goes up by one, rawEvent.sequence_id keeps counting, and audio_window_start / audio_window_end remain relative to the start of the session, so all turns share one timeline.
- If your agent or a turn-taking model should decide when the caller has finished, connect with
commit_mode=manual. The server still sendspartialupdates, but a pause does not end the turn. Send{"type": "Finalize"}to end it. If there was no pending speech,finalis still sent with an emptytranscript. - Any other
commit_modevalue closes the connection with code4002and the messagecommit_mode must be vad or manual.
Keeping the connection open
While you are not sending audio, for example while your agent is speaking, send a KeepAlive message so the connection is not closed for inactivity:
Prefer KeepAlive over streaming silence. Silence still counts as audio on the wire.
If the server receives no audio and no KeepAlive for too long, it sends an Error message and closes the connection with code 4008. See Errors.
Reading results
A partial message:
A final message has the same shape. rawEvent.event is EndOfTurn, and rawEvent also includes trigger and words:
Word times are already on the session timeline, so you don’t need to convert them. Quote rawEvent.request_id when you contact support.
Authentication
Speech to Text does not accept tokens from GET /v1/auth/token.
Query parameters
Concurrency
Each open Speech to Text connection uses one slot until it closes, whether or not you’re sending audio. Speech to Text limits are separate from Text to Speech concurrency. If you hit the limit, new connections close with code 4004. See Rate Limits & Concurrency for plan details.
Best practices
- Replace
partialtranscripts, don’t append them. Eachpartialcontains the whole turn so far. Use thefinaltranscript as the completed turn. - Send audio in small frames. Send 20 to 100 ms of audio per frame. Larger frames delay transcription.
- Stream at real-time pace when sending pre-recorded audio.
- Send your telephony codec as-is. If your provider sends 8 kHz µ-law, declare
mulawat8000instead of converting the audio yourself. See Audio formats. - Wait for
finalafter a pause. You do not need to sendFinalizeon each turn. - Keep one connection per call. Keep sending audio between turns rather than reconnecting.
- Handle errors by close code, not by message text. See Errors.
- Quote
rawEvent.request_idwhen you contact support.
FAQs
Do I get partial (interim) transcripts?
Yes. partial messages show the transcript of the current turn while the caller is speaking. Each one replaces the previous one. When the turn ends, you receive a final message.
When does a turn end?
When the caller pauses, or as soon as you send Finalize. With commit_mode=manual, only when you send Finalize or CloseStream. See Ending a turn.
Can I transcribe a recorded file?
Yes, by streaming it over the WebSocket, as in the WAV example above. There is no separate file or batch transcription endpoint.
What happens to stereo audio?
Stereo input is mixed down to mono before transcription. Each channel is not transcribed separately.
Can it tell different speakers apart?
No. Speaker diarization is not available. Audio with several speakers is transcribed as a single stream.
Can I change the language mid-session?
No. Model, language, keywords and the audio format are set when you connect. Open a new connection to change them.
Is my audio stored?
Audio is processed for transcription. See FAQ for how Murf handles data security and retention.
How am I billed?
$0.12 per hour of audio, billed per second. Enterprise customers can get custom pricing. When your balance runs low, the server sends one QuotaWarning message per session. If credits run out, the connection closes with code 4005.