Guide · Speech APIs
Use Fourier TTS with an OpenAI-compatible speech client.
Already using OpenAI's speech API? Change three values and your code speaks Hindi, English, Gujarati, Tamil or Telugu with Fourier TTS. Just set response_format: we don't do MP3, and without it you get raw 48 kHz PCM.
Only the base URL, the model and the voice change.
The base URL, the model and the voice. Keep the key on your server, never in a browser or mobile app.
| Setting | Mira value |
|---|---|
| Base URL | https://sandbox.voice.miraiminds.co/v1 |
| Request path | /audio/speech, under that base URL |
| Model | mira-tts (the older mira-tts-v51 still works as an alias) |
| Voice | ashu, neha, shruti or sameer; neha if you leave it out |
| Output | Always set response_format |
| Input | Up to 2,000 characters |
Fourier TTS costs ₹1.80 per 1,000 characters. Building a whole phone agent? Those cost ₹1 a minute on our volume plan; see AI calling.
For a key, open Developers in the sandbox and press Create key. The sk_live_ key shows once and works across the v2 API. The same handler also sits at POST /v2/tts, which takes text in place of input.
Your first request saves a WAV file.
This saves a WAV file and spends a few paise. Put your key in MIRA_API_KEY first.
curl --fail-with-body \
https://sandbox.voice.miraiminds.co/v1/audio/speech \
-H "Authorization: Bearer $MIRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mira-tts",
"voice": "neha",
"response_format": "wav",
"input": "नमस्ते, आपका ऑर्डर तैयार है।"
}' \
--output speech.wav
If it fails, --fail-with-body writes the error into speech.wav, so check before you press play.
Pick the format and sample rate you need.
response_format |
You get | Streams? |
|---|---|---|
pcm |
Raw signed 16-bit little-endian mono, no header | Yes |
mulaw (also ulaw, pcm_mulaw) |
Raw G.711 μ-law, one byte per sample | Yes |
alaw (also pcm_alaw) |
Raw G.711 A-law, one byte per sample | Yes |
wav |
A playable 16-bit mono file | No, it comes when synthesis ends |
sample_rate takes 8000, 16000, 22050, 24000, 44100 or 48000, with μ-law and A-law at 8000 or 16000 only. Defaults are 48000 for pcm and wav, 8000 for μ-law and A-law. A rate in the format, like pcm_16000, wins; a conflicting sample_rate gets a 400.
On a phone line, ask for the line’s format and forward chunks as they come. Most lines carry 8 kHz μ-law, so ulaw_8000 needs no decoding or resampling.
You can stream with the OpenAI Python SDK.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["MIRA_API_KEY"],
base_url="https://sandbox.voice.miraiminds.co/v1",
)
with client.audio.speech.with_streaming_response.create(
model="mira-tts",
voice="ashu",
response_format="pcm",
input="चलिए, आपका order कल deliver होगा।",
extra_body={"sample_rate": 16000},
) as response:
print(response.headers.get("x-sample-rate"), response.headers.get("x-audio-encoding"))
with open("speech_16k.pcm", "wb") as out:
for chunk in response.iter_bytes():
out.write(chunk) # raw s16le mono at 16 kHz; feed a player here instead
We ran this with openai 1.109.1 against the sandbox on 16 October 2026. It printed 16000 pcm_s16le and wrote 16 kHz raw PCM.
Play chunks as they arrive, or there’s no point streaming. For live conversations, the WebSocket endpoint is better: one connection per call, text as your model writes it, and one message to stop when the caller interrupts.
The headers tell you how to play the audio.
Every 200 carries these:
| Header | Meaning |
|---|---|
X-Request-Id |
Request ID (tts_…), as in your request log |
X-Chars-Billed |
Characters billed |
X-Cost-Paise |
Cost, once it completes |
X-Sample-Rate |
Sample rate you got |
X-Audio-Encoding |
pcm_s16le, mulaw or alaw |
X-Mira-Model |
The build that made it, like miraiminds/mira-tts-v53 |
Raw audio has no header, so read X-Sample-Rate and X-Audio-Encoding before you play it. Get them wrong and you hear noise, or the wrong speed. Note X-Mira-Model when you compare releases. GET /v2/tts/requests lists every request with first_byte_ms, total_ms and cost.
Existing adapters often trip on OpenAI’s defaults.
Adapters often bake in OpenAI’s defaults. Check yours doesn’t:
- reject
nehaorshrutias unknown voices, - ask for MP3 unless you override it,
- assume a rate, like 24 kHz, instead of reading
X-Sample-Rate, - buffer the whole response even though we stream it.
On Pipecat, use pipecat-mirai instead of the OpenAITTSService workaround; see the Pipecat guide. Anywhere else, listen to what actually plays.
These are the errors you might see, and the fixes.
Errors carry X-Request-Id. Quote it when you ask us for help.
400 invalid_request: fix the field it names, such as empty input, an unknown voice or a format we don’t do.401 unauthorized: check theAuthorization: Bearer sk_live_…header.402 insufficient_balance: top up. Nothing was made or charged.404 model_not_found: usemira-tts.429 at_capacityorrate_limited: wait forRetry-After, then resend.502 upstream_error: retry.503 fleet_offline: wait forRetry-After. Neither is charged.
Cap retries on a live call: a sentence that plays after the moment has passed is worse than none. Our request log keeps only the first 48 characters of each input. The latency guide helps you tell a slow request from a playback problem.
Sources
These are the references this guide is built on.
References reviewed on . Measurement dates and experimental limits are stated in the article. Check current API and runtime documentation when integrating.
- docs.miraiminds.co
- Fourier TTS quickstart: formats, headers, limits and errors
- docs.miraiminds.co
- Streaming text to speech over WebSocket
- docs.miraiminds.co
- Voice catalogue
- docs.miraiminds.co
- Pipecat integration
Questions
These are the questions developers ask us most.
What base URL and model should an OpenAI speech client use?
Base URL https://sandbox.voice.miraiminds.co/v1 and model mira-tts. Voices are ashu, neha, shruti and sameer. Always set response_format.
Can I keep an OpenAI client's default MP3 output?
No. mp3 returns a 400 listing what works: pcm, wav, mulaw (or ulaw) and alaw, plus forms like pcm_16000 and ulaw_8000. Leave the format out and you get raw 48 kHz PCM.
How do I get audio at 8 or 16 kHz through the OpenAI SDK?
Pass sample_rate in the SDK's extra_body, or use a format with the rate in it, like pcm_16000. X-Sample-Rate on the response confirms it.
Will any framework with an OpenAI TTS adapter work unchanged?
Not always. The request shape matches, but the defaults may not. Check the adapter's voice list, default format and assumed sample rate. On Pipecat, use pipecat-mirai instead of OpenAITTSService.
Still deciding? Ask us.
Fifteen minutes with the team that builds it. Bring your script, or your hardest call.
Book 15 minutes