POST /v1/audio/transcriptions protocol, so an OpenAI SDK can call it once
you change the base URL and the model name. For live audio, the same key opens
a WebSocket that sends text back while the person is still talking.
1. Get a key
Open the console, go to Developers and press Create key. You do not need an access code. The first time, the console asks for your work email and sends you a confirmation link; open it, then press Create key again. The key is ask_live_ secret, and the
console shows it only once. We store only its hash, so we cannot recover a
lost key; you rotate it instead. The same key works for speech to text, text
to speech and the rest of the v2 API, and draws on the same
wallet.
2. One request
Send the audio as a multipart form:- cURL
- Python (OpenAI SDK)
200 OK
text. We wait up to 30 seconds plus
half the clip’s length for the transcript (90 seconds for a 120-second clip),
so give your client a timeout of 120 seconds.
OpenAI’s
prompt, temperature and timestamp_granularities are accepted and
ignored, so an OpenAI client that sends them works unchanged.
8 kHz μ-law straight off a phone line
Response formats
json, the default, is the text alone. text is the same text as a plain
body (text/plain; charset=utf-8), with no JSON around it. verbose_json adds
the language as its full code, such as gu-IN even when you sent gu, the
audio’s length in seconds, and one segment for each utterance we found, with
where it starts and ends in the clip. srt and vtt are not offered.
verbose_json
What comes back
Every200 carries its own accounting in headers:
Every error after authentication also carries
X-Request-Id. Quote it when
you ask us about a failed request.
3. Stream it
The socket takes audio as it is captured and sends back partial transcripts as the words are recognised, then one final transcript for each utterance:Authorization: Bearer header, as on every other
request. This script streams a WAV file as if it were live: it opens an
utterance with speech_start, sends the audio in 20 ms audio_input
messages, closes the utterance with speech_end, and ends the session with
end.
stream.py
Output
ffmpeg -i call.mp3 -ac 1 -ar 16000 -sample_fmt s16 hello.wav. With
websockets older than 14, pass extra_headers= instead of
additional_headers=.
The script sends the file as one utterance. With manual endpointing, one
utterance can run for at most 60 seconds: past that you get a fatal
utterance_too_long, the socket closes with 1011, and that utterance gets no
final. For longer audio, send speech_end at a pause at least every 25
seconds, or connect with endpointing=vad and we cut the utterances for you. The
WebSocket reference has every message and event, both
endpointing modes, phone audio and the close codes. A browser connects with a
short-lived stream token
instead of your key.
4. Pipecat
If you build on Pipecat, install our integration withuv add "pipecat-mirai>=0.6.0" and put MiraiSTTService where your STT
service was:
For phone calls
- Send the line’s audio as it is. Twilio and Plivo carry 8 kHz μ-law:
connect with
encoding=mulaw&sample_rate=8000and forward each media payload. Exotel carries 8 kHz 16-bit PCM:encoding=linear16&sample_rate=8000. Don’t resample to 16 kHz first; that adds bytes and nothing the model can use. - Keep one socket per call. Open it when the call connects and send
endwhen it hangs up. - Use your own VAD if you have one. With
endpointing=manual, the final comes back straight after yourspeech_end, with no silence wait on our side. Send the half second of audio from before your VAD fired right afterspeech_start, so the first word is not clipped.
Billing
₹18 per hour of audio, on HTTP and on the socket. That is 0.5 paise a second. We charge on the seconds of audio we received, rounded up to the next second, with a minimum of 1 second, and round the price up to the next paisa. A 20-second clip costs 10 paise; a 3-minute call streamed in full costs ₹0.90.- HTTP: charged once the transcript is written. A request that fails or times out is not charged.
- Socket: you pay for the audio you send, silence included, however the
session ends: with
end, with a closed socket, on a timeout or on an error. With manual endpointing you can send audio only around speech, but keep the half second beforespeech_start. A session longer than 5 minutes is charged in parts as it runs, and the parts add up to what the whole session would cost.
402 insufficient_balance and nothing is transcribed. If the
wallet runs out during a long session, the session ends with
insufficient_balance after
its last final.
Each charge is one debit row on the same wallet your calls draw
from:
GET /v2/wallet/transactions
Live and offline transcription cost the same: offline
transcription of recordings is ₹18 per
hour too, charged once when the job completes.
Limits
We refuse a request over the session limit instead of queueing it. Honour
Retry-After and send it again; a refused request costs nothing. The socket
has its own limits on message size, utterance length and idle time, listed in
the WebSocket reference.
The limit is raised on request, with no change to your code. If you run many
calls at once, ask your Mirai contact for a little more than your peak number
of simultaneous calls.
Your request log
We log every request and every session, and you can read the log yourself:200 OK
GET /v2/stt/requests/{id} returns a single row.
A row holds no audio and no transcript, only what was used and what it cost.
When something fails
Errors on the HTTP endpoint use the same envelope as the rest of the API:
The socket refuses a connection with the same codes before the upgrade, and an
open session reports errors as
error events. Both are listed in the
WebSocket reference. If
you are stuck on something this page does not cover, reply on your onboarding
thread, where a person reads it.