Speech-to-speech
Run a vendor realtime voice model through the Router — provider price plus 5%, one key, one host.
The Router speaks the vendors' own realtime wire protocols, so an existing speech-to-speech client works by swapping only the host and the API key. The Router holds the vendor socket, meters the session, and bills the provider's published price + 5% against your Speko balance — no vendor key of your own, no per-vendor billing.
Endpoints
| Protocol | Route | Models |
|---|---|---|
| OpenAI / xAI Realtime | wss://router.speko.dev/v1/realtime?model=<id> | gpt-realtime-2, gpt-realtime-2.1, gpt-realtime-2.1-mini, grok-voice-3.0, grok-voice-think-fast-2.0 |
| Gemini Live (BidiGenerateContent) | wss://router.speko.dev/v1/bidi | gemini-3.8-live, gemini-3.8-live-extended-thinking |
| GPT-Live | wss://router.speko.dev/v1/live | gpt-live-1 |
For /v1/realtime the model rides the model query parameter; for /v1/bidi
and /v1/live it rides the first setup/session frame, exactly as each vendor
defines it. The full, per-organization catalog is GET /v1/models (kind s2s).
Authentication
Every upgrade carries your Speko key as a bearer token:
Authorization: Bearer sk_speko_...An Idempotency-Key header is currently required on the WebSocket upgrade
(any non-blank string up to 256 bytes — a UUID per session is the right
default). A future release makes it optional on the voice routes and mints one
server-side when absent; until then, send one. Browsers cannot set custom
headers on a WebSocket upgrade, so terminate Router voice sockets from your
backend.
Pricing
The provider's published per-minute (or per-token) realtime price + 5%, settled per second against your Speko balance and shown on the usage and activity pages. There is no Speko flat minute on the Router — see billing.
OpenAI SDK
Point the Realtime client at the Router and send your Speko key:
import { OpenAIRealtimeWebSocket } from "openai/realtime/websocket";
const rt = new OpenAIRealtimeWebSocket({
model: "gpt-realtime-2.1",
baseURL: "wss://router.speko.dev/v1",
apiKey: process.env.SPEKO_API_KEY,
// Send on the upgrade until Idempotency-Key becomes optional on voice routes.
headers: {
"Idempotency-Key": crypto.randomUUID(),
},
});LiveKit Agents
Give the OpenAI/xAI realtime plugin the Router base URL, the Speko key, and the upgrade header:
from livekit.plugins.openai.realtime import RealtimeModel
model = RealtimeModel(
model="gpt-realtime-2.1",
api_key=os.environ["SPEKO_API_KEY"],
base_url="wss://router.speko.dev/v1",
# LiveKit forwards extra headers on the realtime upgrade.
extra_headers={"Idempotency-Key": str(uuid.uuid4())},
)For Gemini Live, use the google realtime plugin against /v1/bidi.
Pipecat
from pipecat.services.openai_realtime import OpenAIRealtimeBeta
llm = OpenAIRealtimeBeta(
api_key=os.environ["SPEKO_API_KEY"],
base_url="wss://router.speko.dev/v1",
session_properties={"model": "gpt-realtime-2.1"},
headers={"Idempotency-Key": str(uuid.uuid4())},
)Errors
Upgrade-time failures (bad key, unknown model, missing idempotency key) return a JSON error envelope before the socket switches protocols; after the upgrade, errors arrive as the vendor's own error events. See errors.