Speech APIs
Hindi speech-to-text API: transcribe calls with Mira
The Hindi speech-to-text you can call on its own today is offline transcription: send a recording or a link to POST /v2/transcriptions, poll the job, and get Hindi in Devanagari and English in Latin script, with speakers and timestamps, for ₹18 per hour of audio. Live recognition runs inside every Mirai voice agent and Realtime session, and a standalone streaming API is in private preview.
Which speech-to-text endpoints exist?
Mirai builds its own speech, recognition and language models and offers them as APIs, alongside voice agents on the same stack. For Hindi speech to text, the endpoint depends on where the audio comes from:
| You have | Use | Billing |
|---|---|---|
| A recording of a call that already happened | POST /v2/transcriptions (offline) |
₹18 per hour of audio |
| A call made by one of your Mirai agents | GET /v2/calls/{id}/transcript, or the transcript in the call.processed webhook |
Part of the call |
| Live audio in your own app or bot | The Realtime API, which sends conversation.item.input_audio_transcription events as the caller speaks |
Per minute, as a call |
| Live audio, recognition only | Standalone streaming recognition, in private preview | Ask Mirai |
Offline transcription is built for phone calls in Hindi and Hinglish. language defaults to auto, which detects the main language; you can set hi or en when detection gets it wrong, and the reference lists the other codes it accepts.
How accurate is Mira STT on Hindi?
On all 10,000 utterances of the RinggAI Hindi ASR benchmark, Mira STT (the v4 fine-tune with a TDT decoder head) scored 9.12% normalised word error rate. It is not the lowest on every subset; other systems in the same comparison do better on some of the corpora. The evaluation report also notes that the package Mirai ships uses a CTC head for latency, which scored 9.85% on the same set. The speech-to-text model page has the full table and method.
Read those numbers for what they are. The benchmark is public read and conversational Hindi, not phone calls, and it measures the recognition model on its own. An offline transcription job is a different pipeline, with several recognition passes, speaker separation and a language-model step that merges them, and the benchmark does not measure its output. To know how it does on your calls, transcribe a sample you have permission to use and have a Hindi speaker review it.
How do you transcribe a recording?
Create a key under Developers in the sandbox. No access code is needed. Then upload the recording as multipart/form-data:
curl -X POST https://sandbox.voice.miraiminds.co/v2/transcriptions \
-H "Authorization: Bearer $MIRAI_API_KEY" \
-H "Idempotency-Key: call-2026-10-02-0412" \
-F file=@call.wav \
-F context="A call to a university admissions desk about a course and its fees" \
-F vocabulary="Mira University, BBA, Aadhaar"
The answer is 202 Accepted with the job, status: "queued". In Python, submit and wait like this:
import os
import time
import httpx
API = "https://sandbox.voice.miraiminds.co"
auth = {"Authorization": f"Bearer {os.environ['MIRAI_API_KEY']}"}
def submit(path: str, idempotency_key: str) -> dict:
with open(path, "rb") as f:
r = httpx.post(
f"{API}/v2/transcriptions",
headers={**auth, "Idempotency-Key": idempotency_key},
files={"file": (os.path.basename(path), f, "audio/wav")},
data={
"context": "A delivery company confirming an order and a refund",
"vocabulary": "refund, order",
},
timeout=600, # the answer comes after the whole file is uploaded
)
job = r.json()
if r.status_code != 202:
raise RuntimeError(f"{job['error']['code']}: {job['error']['message']}")
return job
def wait(job_id: str, timeout_secs: int = 3600) -> dict:
deadline = time.monotonic() + timeout_secs
delay = 1.0
while time.monotonic() < deadline:
r = httpx.get(f"{API}/v2/transcriptions/{job_id}", headers=auth, timeout=30)
if r.status_code in (429, 503):
time.sleep(float(r.headers.get("Retry-After", "5")))
continue
job = r.raise_for_status().json()
if job["status"] in ("completed", "failed"):
return job
time.sleep(delay)
delay = min(delay * 1.5, 5) # quick at first, then every 5 seconds
raise TimeoutError(job_id)
job = wait(submit("call.wav", idempotency_key="call-2026-10-02-0412")["id"])
if job["status"] == "failed":
print(job["error"]["code"], job["error"]["message"])
else:
for seg in job["segments"]:
print(f"{seg['start']:6.2f} {seg.get('speaker_id', '-')} {seg['speaker']}: {seg['text']}")
print(job["cost"])
A job moves through queued, decoding and merging to completed or failed. The docs put a typical job at about 10 seconds plus 15% of the recording’s length. While it is merging, the job carries a draft: the strongest single recognition pass, with timestamps and no speakers, in which English often appears in Devanagari. Show it as provisional and replace it when the job completes.
A recording over 45 MB goes by link: send JSON with an https url (up to 200 MB), such as a pre-signed link to your storage that stays valid for at least 5 minutes.
What does a finished transcript look like?
A completed job has text, segments and diarization. Each segment has a speaker role (Agent, Customer or Other), a speaker_id such as spk0, start and end in seconds, and the text as spoken. From the docs’ example:
{
"speaker": "Customer",
"speaker_id": "spk1",
"start": 7.21,
"end": 11.32,
"text": "yes tell me I wanted to ask about the BBA course fees"
}
Roles are worked out from what each person says and can be wrong, so group lines by speaker_id. On an agent-customer call the agent is spk0. Speaker separation also silences ringing, caller tunes and hold music before transcription and lists those spans in diarization.non_speech. Send words: true for word timings on each segment.
What can go wrong?
| What you see | Why | What to do |
|---|---|---|
failed with transcription_failed |
The file could not be transcribed | Check that it plays and contains speech; WAV and MP3 work everywhere |
failed with audio_too_long |
Longer than 2 hours | Split the recording |
failed with engine_restarted, job_lost, timed_out or submit_interrupted |
The job was interrupted on Mirai’s side | Submit again; failed jobs are free |
degraded: true |
The language-model step couldn’t write the transcript, so you got the single best pass | Free; send it again with a new Idempotency-Key if you need the full transcript |
413 request_too_large |
Upload over 45 MB, or a linked file over 200 MB | Send a link, or split the file |
429 at_capacity |
20 unfinished jobs in the workspace | Wait for Retry-After (30 seconds) |
429 rate_limited |
120 new jobs in the past hour, or your key’s request rate | Wait for Retry-After; polling counts towards the request rate |
402 insufficient_balance |
Wallet at zero or below | Top up and retry with the same Idempotency-Key |
| The less-used language reads worse | A Hindi greeting in an English call, or the reverse | Add context and vocabulary |
Idempotency keys for transcription never expire, and a reused key returns the original job even if you send a different file. Derive the key from your own recording ID. Transcripts have no published retention period and there is no delete endpoint yet, so copy each finished transcript into your own storage.
What does it cost?
₹18 per hour of audio on every plan, charged once when the job completes, by the recording’s length to the millisecond and rounded up to the paisa. A 23-second call costs ₹0.12 and a five-minute call ₹1.50. Degraded and failed jobs are free. Each charge is one wallet transaction with kind: "transcription" and the job ID as its reference. The pricing guide covers the other APIs.
Building a full phone agent instead? Agents start at ₹1 a minute at volume; see AI calling.
Common questions
Is there a streaming Hindi speech-to-text API?
Streaming recognition runs inside every Mirai voice agent and every Realtime session, which sends the caller's words as transcription events. As a standalone API it is in private preview, so ask Mirai for access.
How much does Mirai's transcription cost?
₹18 per hour of audio, charged once when a job completes, for the recording's length to the millisecond, rounded up to the paisa. A five-minute call costs ₹1.50. Degraded and failed jobs are free. Prices exclude GST.
How accurate is Mira STT on Hindi?
On all 10,000 utterances of the RinggAI Hindi benchmark, Mira STT scored 9.12% normalised word error rate. It is not the lowest on every subset of that benchmark, and the benchmark uses public read and conversational speech, so it is not a measure of accuracy on phone calls.
Does the transcript translate Hinglish into Hindi or English?
No. Hindi comes back in Devanagari and English in Latin script, the way the speakers switched, though common English loanwords can stay in Devanagari. Nothing is translated.
Does Mirai keep my audio?
The docs say the API does not keep it: an upload passes through a temporary file deleted when the request ends, and a link is fetched once. The transcript is kept so the job can return it, with no published retention period, so copy transcripts into your own storage.
Sources and API references
References reviewed on . Measurement dates and experimental limits are stated in the article. Check current API and runtime documentation when integrating.