GOPURA

Speech & transcription

OpenAI-compatible text-to-speech and speech-to-text, priced per character, per second, or per audio token.

Gopura serves the two OpenAI audio endpoints, so client.audio.speech.create and client.audio.transcriptions.create in any OpenAI SDK work after the base URL swap:

  • POST /v1/audio/speech turns text into audio (text-to-speech).
  • POST /v1/audio/transcriptions turns audio into text (speech-to-text).

Speech models show modality: "speech" on /v1/models and transcription models show modality: "transcription". The catalog includes OpenAI TTS and Whisper, Gemini 3.8 TTS and 3.5 Transcribe, Microsoft MAI-Voice and MAI-Transcribe, Grok, and Fish Audio.

Text to speech

curl -s https://api.gopura.net/v1/audio/speech \
  -H "Authorization: Bearer $GOPURA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/tts-1",
    "input": "Welcome to Gopura.",
    "voice": "nova",
    "response_format": "mp3"
  }' -o welcome.mp3

Or with the SDK:

const speech = await client.audio.speech.create({
  model: 'openai/tts-1',
  input: 'Welcome to Gopura.',
  voice: 'nova',
});
await fs.promises.writeFile('welcome.mp3', Buffer.from(await speech.arrayBuffer()));

Request

FieldMeaning
modela speech model id from the catalog
inputthe text to speak, up to 4,096 characters
voicethe provider's voice id; omit it to get the model's default voice
response_formatmp3, opus, aac, flac, wav or pcm
speed0.25–4.0 (OpenAI models)
instructionsa speaking-style prompt (Gemini TTS)
languageGopura extension: a language hint for multilingual voices

Each model's supported_parameters on /v1/models lists which of these optional fields it honours.

Voices.

  • OpenAI models: alloy, ash, coral, echo, fable, nova, onyx, sage, shimmer.
  • Gemini TTS: Google's 30 prebuilt voices, such as Kore, Puck and Zephyr.
  • Other providers take their own voice ids unchanged.

An unknown voice returns a 400 that includes the provider's message, and for OpenAI that message lists the valid voices.

Response

The body is the raw audio file, exactly as OpenAI returns it. Because the body is binary, the billing details come back as headers:

HeaderMeaning
Content-Typethe format you actually received (audio/mpeg, audio/wav, audio/ogg, audio/aac, audio/flac, audio/pcm)
X-Gopura-Costthe exact charge in USD
X-Gopura-Characterscharacters in input
X-Gopura-Input-Tokens / X-Gopura-Output-Tokenstoken-priced models only
X-Gopura-Warninganything the provider ignored or substituted

Content-Type is read from the audio itself, not copied from your request. Gemini TTS only produces WAV (24 kHz, 16-bit mono). If you ask it for mp3 you get WAV, and the response says so:

Content-Type: audio/wav
X-Gopura-Warning: Unsupported output format: mp3. Using wav instead.

pcm is raw 16-bit little-endian samples at 24 kHz with no header.

Transcription

Upload the file as multipart, exactly as with OpenAI:

curl -s https://api.gopura.net/v1/audio/transcriptions \
  -H "Authorization: Bearer $GOPURA_API_KEY" \
  -F model=openai/whisper-1 \
  -F file=@meeting.mp3 \
  -F language=en
const transcript = await client.audio.transcriptions.create({
  model: 'openai/whisper-1',
  file: fs.createReadStream('meeting.mp3'),
});
// transcript.text, transcript.usage.cost

If your client can't send multipart, send JSON with the audio as a base64 data URL instead:

{ "model": "openai/gpt-4o-mini-transcribe", "file": "data:audio/mpeg;base64,SUQzBAAAAAAA…" }

Request

FieldMeaning
modela transcription model id from the catalog
filethe audio file (mp3, mp4/m4a, wav, webm, ogg, flac, aac), up to 25 MB
languageISO-639-1 hint, e.g. hi (OpenAI models)
promptvocabulary or style hint, e.g. product names (OpenAI models)
response_formatjson (default), text or verbose_json

language and prompt currently reach only the OpenAI models. If you send them to another model, the request still succeeds and an X-Gopura-Warning header says which ones were ignored, so they are never dropped silently.

Response

{
  "text": "Hello from Gopura. This is a voice test.",
  "usage": { "type": "duration", "seconds": 3, "cost": 0.000375 }
}

verbose_json adds language, duration, and segments[], each with {id, start, end, text}, where the model provides them. With response_format: "text" the body is plain text and the charge is in the X-Gopura-Cost header.

Pricing

Every model is priced in the unit its provider bills in. Our margin is already included in every price on /v1/models, and the charge is returned with each response, so you never have to reconstruct it.

Pricing on /v1/modelsUsed byHow the charge is calculated
pricing.characterOpenAI TTS, MAI-Voice, Grok TTS, Fish Audiocharacters in input, counted as UTF-16 code units (so an emoji counts as 2)
pricing.secondWhisper, MAI-Transcribe, Grok STT, Fish Transcribeaudio duration, rounded up to the next whole second
pricing.prompt / .completionGemini TTS, Gemini Transcribe, GPT-4o Transcribetext and audio tokens; audio is about 25 tokens per second on Gemini

Some reference points at today's prices:

  • openai/tts-1: $18.75 per million characters.
  • google/gemini-3.8-flash-tts: about $0.017 per minute of generated speech.
  • openai/whisper-1: $0.0075 per minute.
  • microsoft/mai-transcribe-2: about $0.125 per hour.

Speech is billed per character, so its charge is known before the request runs. A transcription's duration is only known once the provider reports it, so the gateway holds an upper bound first and charges the reported duration. For WAV uploads the bound is exact, read from the file header.

Languages

Gemini 3.8 TTS, MAI-Voice and the OpenAI models are multilingual. We have verified Hindi end to end, both synthesising it and transcribing it back, on openai/tts-1, openai/whisper-1, openai/gpt-4o-mini-transcribe and google/gemini-3.5-transcribe. Check a sample in your own target language before you rely on it.

Limits and latency

  • Speech: 4,096 characters per request. Split longer text at sentence boundaries.
  • Transcription: 25 MB per file.
  • The gateway gives speech 120 seconds and transcription 10 minutes. A hung provider returns a clean 504 timeout, and you are not billed.
  • Transcription runs at roughly 15 seconds per minute of audio: a 6-minute recording took about 90 s on Whisper. Set your client timeout to match, or split long recordings and transcribe the pieces in parallel.
  • Measured on single samples on 2026-10-11, so treat these as indicative:
    • Speech takes about 1–2 s on every model.
    • Transcribing a 4-second clip takes about 1 s on Whisper, GPT-4o mini, Grok and Fish, and about 2 s on Gemini.
    • microsoft/mai-transcribe-2 is the cheapest but took about 22 s for a 4-second clip.

Not yet available

The following are not available yet:

  • Streaming speech output (stream_format: "sse").
  • Streaming or realtime transcription (stream: true; the -live and -streaming model variants).
  • Realtime voice-agent sessions.
  • srt and vtt subtitle formats.

A request that asks for one of these gets a clear 400 rather than being silently ignored.