Speko Docs
RouterReference

API reference

Every router endpoint, its parameters, and which controls are Speko-specific.

Base URL https://api.speko.ai/v1. Authenticate with Authorization: Bearer <your router key>.

The request and response shapes are OpenAI's, so an OpenAI client works unchanged. Speko-specific controls ride in X-Speko-* headers, never in the body — see routing.

Set model to auto to let the router rank. Any id from GET /v1/models pins that model instead.

EndpointStageReturns
POST /v1/chat/completionsLLMCompletion, or SSE when stream: true
POST /v1/audio/transcriptionsSTTTranscript JSON
POST /v1/audio/speechTTSAudio body
POST /v1/audio/speech/streamTTSAudio chunks — see TTS streaming
GET /v1/modelsEvery model, its measured numbers and languages
GET /v1/routing/previewThe candidate the router would pick, without calling it
POST /v1/synthesizeTTSAudio body — Speko-native shape, when OpenAI's does not fit

POST /v1/chat/completions

curl -X POST https://api.speko.ai/v1/chat/completions \
  -H "Authorization: Bearer $SPEKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "auto", "messages": [{ "role": "user", "content": "Say hello." }] }'
{
  "id": "chatcmpl-…",
  "model": "openai:gpt-4.1",
  "choices": [{ "index": 0, "message": { "role": "assistant", "content": "Hello." } }]
}

The x-route response header carries Provider/model for the request that actually served you.

modelstringrequired

auto to route, or a pinned id such as openai:gpt-4.1.

messagesarrayrequired

Standard OpenAI message array.

streambooleandefault: false

Server-sent events. Note that a streamed request cannot be retried once a byte has reached you, so it gets one upstream attempt.

max_tokensinteger

Also accepted as max_token and max_completion_tokens. The router renames it to whichever spelling the chosen provider expects, so send whichever your client already sends.

Everything else in the body is forwarded to the provider untouched, temperature and tools included.

POST /v1/audio/speech

curl -X POST https://api.speko.ai/v1/audio/speech \
  -H "Authorization: Bearer $SPEKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "auto", "input": "Your appointment is confirmed.", "response_format": "pcm" }' \
  --output confirmation.pcm

The body is the audio itself, not JSON.

inputstringrequired

The text to speak.

modelstringrequired

auto to route, or a pinned id such as cartesia:sonic-3.5.

voicestring

An OpenAI preset name (alloy, nova) or a provider voice id. A voice id belongs to one provider, so sending one restricts routing to the provider that can serve it. Omit it and the router picks a default for whichever provider it chose. A voice set on the key fills this in when you omit it.

instructionsstring

Delivery direction in plain language — "speak warmly". Not SSML. It goes in the provider's system-instruction field, so it is never spoken aloud. Measured to change delivery on Gemini TTS; other providers largely disregard it.

response_formatstringdefault: pcm

pcm returns raw 24 kHz mono 16-bit little-endian audio, no container. That is what a telephony or WebRTC pipeline wants, and it streams.

wav wraps the same audio in a RIFF header so a player can open it. It cannot stream: the header states the total length, so the audio must be complete first.

mp3 and opus are refused with 400 invalid_parameter. Every provider is asked for the same PCM, so failover cannot change the format mid-request, and an encoded container would need a codec in the audio path.

speednumber

Forwarded to providers that support it and dropped for those that do not.

POST /v1/audio/transcriptions

curl -X POST https://api.speko.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $SPEKO_API_KEY" \
  -F model=auto \
  -F file=@support-call.wav
{ "text": "Thanks for calling, how can I help?" }
filefilerequired

Audio, as multipart/form-data.

modelstringrequired

auto to route, or a pinned id such as deepgram:nova-3.

languagestring

A BCP 47 tag. Read from the body when no X-Speko-Language header is present, so an OpenAI client that already sets it needs no Speko header at all.

GET /v1/models

No key required. Returns every model with its measured numbers, plus the languages array that is the live list of what you can route — see languages and accents.

id values are exactly what you pin in model or in a key's chain.

GET /v1/routing/preview

A dry run. Returns the candidate the router would choose, without calling any provider or costing anything.

stagestringrequired

stt, llm, or tts.

languagestringrequired

A BCP 47 tag.

objectivestring

latency, cost, quality, or balanced.

POST /v1/synthesize

Speko's native TTS endpoint, for when OpenAI's shape does not fit. It takes text rather than input and uses your voice id verbatim instead of mapping it through OpenAI's preset names.

Reach for /v1/audio/speech unless you specifically need that.

On this page