Skip to main content
For the endpoint contract see Text-to-speech and Speech-to-text. This guide covers practical recipes. Both endpoints work with client.audio.speech.create(...) and client.audio.transcriptions.create(...) for the common case. Neither is unconditionally drop-in — TTS can defer to a job on a long render (see the warning below), and STT drops a couple of OpenAI parameters silently. The gaps are called out in place below, and the full picture across every operation is the compatibility matrix.

Text-to-speech

Pick a voice and model

Voice character is fixed per voice — you can’t fine-tune them. To pick, render the same line in 3–4 voices and listen.

Save to file

python

Sample output

“Welcome to Infery — one API for every AI model.” Generated with gemini-2.5-flash-tts, voice Kore.
For a fal/replicate-routed voice, synthesis that outruns the gateway’s wait budget answers a JSON error (not audio bytes) carrying a job_id, in place of the audio/* response client.audio.speech.create(...) expects. The request is still running and still billed — collect the finished audio from GET /v1/images/jobs/{job_id}, which answers a signed download URL. The OpenAI SDK has no path for “JSON where I expected bytes”; a caller that doesn’t check for it will treat this as a parse error rather than a job to poll.

Stream to a player

For long passages, stream the bytes directly to the user’s audio element instead of downloading then playing:
python

Format choice

Pacing

speed is 0.25 → 4.0. Most listeners are comfortable at 0.95–1.15 . Speeding past 1.5 is intelligible but tiring; slowing below 0.85 gets robotic.

Speech-to-text

Quick transcription

python

Long-form audio (>25 MB)

Whisper-1 caps at 25 MB. For longer recordings, split first:
python
Use 64 kbps mono MP3 — Whisper doesn’t benefit from higher bitrate, and you stay well under the size cap.

Subtitle export

response_format="srt" or "vtt" renders subtitles — but the body is always JSON, with the subtitle document inside text. Read that field rather than writing the response out whole:
python
The OpenAI SDK assumes srt/vtt/text come back as a bare document and hands you the raw body, which here is the JSON envelope — writing it straight to a file produces an unplayable subtitle track. Either use the HTTP call above, or parse the SDK’s string as JSON and take ["text"].

Timestamps

response_format="verbose_json" returns segment-level timestamps:
python
Word-level timestamps are not supported. timestamp_granularities=["word"] is accepted by the SDK but dropped before the request reaches the provider, so tr.words comes back empty and iterating it raises. Segment timestamps are the finest granularity available today.

Translation

There is no /v1/audio/translations endpoint, so client.audio.translations.create(...) fails with a 404. Transcribe first, then translate with a chat completion:
python

Round-trip: voice agent

Combining STT → chat → TTS gives you a basic voice agent:
python
End-to-end latency is dominated by the chat call. Realtime (WebSocket bidirectional voice) is on the roadmap.

Costs at a glance

  • TTS: ~15per1Mcharactersontts1, 15 per 1 M characters on `tts-1`, ~30 on tts-1-hd
  • Whisper STT: ~$6 per hour of audio
  • Long meetings (1 h) typically cost less than the chat completion that follows them

Pitfalls

  • Wrong language hint drops STT accuracy. Auto-detect is good but a language= hint is better when known.
  • Quiet/clipped recordings — Whisper handles noise well but not clipping. Normalise levels before transcribing.
  • TTS swallowing punctuation — write naturally; “Hi—how are you?” reads better than “Hi how are you”.
  • Long base64 audio over JSON wastes 33% bandwidth vs. multipart. Use multipart unless you have a JSON-only client.