Quickstart

Setup

export SPEKO_API_KEY=sk_live_...
pip install openai
export SPEKO_API_KEY=sk_live_...
npm install openai

Speech-to-text

import os
from openai import OpenAI

speko = OpenAI(api_key=os.environ["SPEKO_API_KEY"], base_url="https://api.speko.ai/v1")

with open("sample.wav", "rb") as audio:
    out = speko.audio.transcriptions.create(
        # "auto" ranks the column. Any id from GET /v1/models pins one.
        model="auto",
        file=audio,
    )
print(out.text)
import { createReadStream } from "node:fs";
import OpenAI from "openai";

const speko = new OpenAI({
  apiKey: process.env.SPEKO_API_KEY,
  baseURL: "https://api.speko.ai/v1",
});

const out = await speko.audio.transcriptions.create({
  // "auto" ranks the column. Any id from GET /v1/models pins one.
  model: "auto",
  file: createReadStream("sample.wav"),
});
console.log(out.text);
Response
x-route: deepgram:nova-3

{"text": "What time do you close on Saturday?"}

LLM

import os
from openai import OpenAI

speko = OpenAI(api_key=os.environ["SPEKO_API_KEY"], base_url="https://api.speko.ai/v1")

reply = speko.chat.completions.create(
    model="auto",
    messages=[{"role": "user", "content": "What time do you close on Saturday?"}],
)
print(reply.choices[0].message.content)
import OpenAI from "openai";

const speko = new OpenAI({
  apiKey: process.env.SPEKO_API_KEY,
  baseURL: "https://api.speko.ai/v1",
});

const reply = await speko.chat.completions.create({
  model: "auto",
  messages: [{ role: "user", content: "What time do you close on Saturday?" }],
});
console.log(reply.choices[0].message.content);
Response
x-route: openai:gpt-5-mini

{"object": "chat.completion", "choices": [{"finish_reason": "stop",
  "message": {"role": "assistant", "content": "We close at six on Saturday."}}]}

Text-to-speech

import os
from openai import OpenAI

speko = OpenAI(api_key=os.environ["SPEKO_API_KEY"], base_url="https://api.speko.ai/v1")

speech = speko.audio.speech.create(
    model="auto",
    # A preset, not a pin: each provider answers it on its own voice.
    voice="alloy",
    input="We close at six on Saturday.",
    response_format="pcm",
)
speech.write_to_file("reply.pcm")
import { writeFile } from "node:fs/promises";
import OpenAI from "openai";

const speko = new OpenAI({
  apiKey: process.env.SPEKO_API_KEY,
  baseURL: "https://api.speko.ai/v1",
});

const speech = await speko.audio.speech.create({
  model: "auto",
  // A preset, not a pin: each provider answers it on its own voice.
  voice: "alloy",
  input: "We close at six on Saturday.",
  response_format: "pcm",
});
await writeFile("reply.pcm", Buffer.from(await speech.arrayBuffer()));
Response
x-route: cartesia:sonic-3.5
content-type: application/octet-stream

reply.pcm - 24 kHz mono PCM

Routes

POST /v1/transcribe Transcribe raw audio with cross-provider routing
POST /v1/synthesize Synthesize raw PCM with cross-provider routing
POST /v1/audio/transcriptions Transcribe audio
POST /v1/audio/speech Synthesize speech
POST /v1/chat/completions Create a chat completion
GET /v1/models List measured models
GET /v1/routing/preview Preview a route without upstream traffic
POST /v1/realtime/sessions Mint a 60-second browser credential
GET /v1/realtime Open a speech-to-speech WebSocket
GET /v1/transcribe/stream Open a realtime transcription WebSocket

Request headers

X-Speko-Objective latency, quality, cost, balanced
X-Speko-Language BCP 47 language tag used for benchmark selection and provider transcription.
X-Speko-Allow Comma-separated providers or provider:model ids to allow.
X-Speko-Deny Comma-separated providers or provider:model ids to exclude.
X-Speko-Max-Price Maximum benchmark price accepted for the selected stage.

Response headers

X-Route Provider and model that served the request
X-Route-Reason objective:score=..;lang=xx(measured|english-proxy|none);model-pin=..
X-Speko-Failover-Count Attempts that failed before this one
X-Speko-First-Byte-Ms Speko's request out to the provider's first byte

Errors

400 invalid_request_body Fix the body.
400 invalid_routing_header Fix the named header.
401 invalid_api_key Replace the bearer key.
413 request_too_large Over the 8 MiB replay limit.
502 all_upstreams_failed Every candidate failed. Retry with backoff.
503 no_candidate Nothing routable matches. Widen the constraints.

Next

LiveKit An AgentSession on one key
Pipecat A pipeline on one key
Models The measured rows the ranking reads
OpenAPI The machine-readable contract
One router for speech-to-text, LLM and text-to-speech.

Speko