docs

Audio

POST/v1/audio/speechbinary audio stream
POST/v1/audio/transcriptionsmultipart/form-data
GET/v1/audio/voicesJSON list

Speech (text-to-speech)

Returns audio bytes. The gateway streams the provider's response through without buffering (chunked transfer), so playback can start before synthesis finishes.

bash
curl "https://api.osmexo.com/v1/audio/speech" \
  -H "Authorization: Bearer $OSMEXO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/tts-1",
    "input": "The gateway routes each request to the best available provider.",
    "voice": "alloy",
    "response_format": "mp3",
    "speed": 1.0
  }' --output speech.mp3
FieldTypeNotes
modelstring, requiredSpeech model id.
inputstring ≤ 40,000 chars, requiredText to speak.
voicestringA voice id from GET /v1/audio/voices for a model that publishes one, or the provider's own voice name otherwise. Omit voice to use the model's default.
response_formatmp3 | opus | aac | flac | wav | pcmDefault mp3. Sets the response Content-Type (audio/mpeg, audio/ogg, audio/aac, audio/flac, audio/wav, audio/pcm). Formats are per model — an ElevenLabs speech model answers mp3, opus or pcm only.
speednumber 0.25–4
routingobjectRouting override.

Response headers include X-Request-Id, X-LLM-Model and X-LLM-Cost-Micro. Speech is priced per character or per audio second depending on the model (see the model's pricing keys).

Streaming behaviour

  • Headers are sent as soon as the provider starts responding; bytes are forwarded as they arrive.
  • Retries and fallback apply only before the first byte is forwarded. A provider failure after that closes the connection early; check that the received byte count matches Content-Length when the provider supplies one, or that the container decodes cleanly.
  • Idempotency-Key is accepted (optional).
typescript
const res = await client.audio.speech.create({
  model: 'openai/tts-1',
  voice: 'alloy',
  input: 'Hello from the gateway.',
  response_format: 'mp3',
});
await fs.promises.writeFile('speech.mp3', Buffer.from(await res.arrayBuffer()));

Voices

GET /v1/audio/voices?model=elevenlabs/eleven-v3 lists the voices a speech model offers, as stable public ids:

json
{ "object": "list", "data": [ { "id": "en-female-ava", "name": "Ava", "language": "en", "gender": "female", "style": ["narration"], "preview_url": null, "default": true } ] }

Pass the id as voice on /v1/audio/speech; omit voice for the model's default. Ids are OSMEXO's own and do not change when the provider behind a model changes. An unknown id is a 400 validation_failed naming voice. preview_url is reserved and is currently always null. A model that does not publish voices (most non-ElevenLabs speech models) returns an empty list — pass the provider's own voice name to voice instead. This endpoint is free: it is not billed.

bash
curl "https://api.osmexo.com/v1/audio/voices?model=elevenlabs/eleven-v3" \
  -H "Authorization: Bearer $OSMEXO_API_KEY"

Transcriptions (speech-to-text)

Upload an audio file as multipart/form-data.

bash
curl "https://api.osmexo.com/v1/audio/transcriptions" \
  -H "Authorization: Bearer $OSMEXO_API_KEY" \
  -F model="openai/whisper-1" \
  -F file=@meeting.mp3 \
  -F language=en \
  -F response_format=json
Form fieldNotes
filerequired. Audio file; total request ≤ 25 MiB.
modelrequired. Transcription model id.
languageISO-639-1 hint (e.g. en).
response_formatjson (default), text, verbose_json, srt, vtt — subject to model support.

Response for json:

json
{ "text": "Welcome everyone, let's get started with the roadmap review." }

verbose_json additionally returns language, duration and segments[] where the provider supplies them. Transcription is priced per audio second.

typescript
const transcription = await client.audio.transcriptions.create({
  model: 'openai/whisper-1',
  file: fs.createReadStream('meeting.mp3'),
});
console.log(transcription.text);

Errors

HTTPcodeCause
400validation_failedMissing input/file/model, out-of-range speed, or an unrecognized voice id.
404model_not_foundUnknown model on /v1/audio/voices.
413request_too_largeMultipart body over 25 MiB.
415unsupported_media_typeTranscriptions called without multipart.
403modality_not_allowedKey scope excludes audio.