Sessions
POST /v1/sessions — create a provider session on the local gateway API.
Create a session
POST /v1/sessions on the Unix socket, with Authorization: Bearer <SPEKO_LOCAL_AUTH_TOKEN> and a required Idempotency-Key header (any non-blank string; bodies are capped at 64 KiB and unknown fields are rejected).
{
"kind": "tts",
"integration": { "name": "custom", "version": "1.0.0" },
"execution": {
"provider_route": "provider_direct",
"credential_source": "managed",
"relay_policy": "forbidden"
},
"request": {
"provider": "auto",
"voice": "voice_123",
"language": "en",
"max_input_characters": 4000
},
"media": { "encoding": "pcm_s16le", "sample_rate_hz": 16000, "channels": 1 }
}kindstringrequiredstt, tts, llm, or realtime.
execution.provider_routestringauto, provider_direct, or speko_relay. auto is request-only — the resolved plan always names a concrete route.
execution.credential_sourcestringmanaged or byok. This is selected independently for every request, so both can coexist in one gateway process.
execution.relay_policystringrequired, allowed, or forbidden.
request.providerstringProvider name, or auto. Managed requests can delegate selection to Speko. BYOK requests resolve auto only when exactly one configured provider supports the session kind. Blank is treated as auto.
request.voicestringProvider voice ID. Always wins when set; when absent, the plan's route voice applies — this exists because a caller sending provider: "auto" cannot know which vendor's voice ID space to use.
request.max_input_charactersnumberRequired for TTS (must be positive); must be absent for every other kind.
mediaobjectRequired for stt, tts, and realtime; forbidden for llm. encoding is pcm_s16le or opus; sample_rate_hz 8000–192000; channels 1–8.
Validation rules
byokcannot usespeko_relay, and cannot setrelay_policy: "required".relay_policy: "required"conflicts withprovider_route: "provider_direct";relay_policy: "forbidden"conflicts withprovider_route: "speko_relay".- Local BYOK sessions require
byok+provider_direct(orauto) +relay_policy: "forbidden", and must namerequest.providerwhen more than one configured BYOK provider supports the kind. integration.nameandintegration.versionmust be provided together.
Idempotency
Reusing an Idempotency-Key with the same body replays the original response with 200; the same key with a different body returns 409 idempotency_key_conflict. Concurrent requests with one key join the same in-flight attempt.
Response
201 Created (or 200 OK on replay):
{
"session_id": "session_...",
"attempt_id": "attempt_...",
"execution": { "placement": "sidecar", "provider_route": "provider_direct", "credential_source": "managed" },
"route": { "provider": "deepgram", "model": "flux-general-en", "region": "eu", "adapter": "deepgram.stt.v1", "transport": "websocket" },
"stream_url": "/v1/sessions/session_.../stream",
"control_plane_request_id": "..."
}The route deliberately omits the provider endpoint's query string and the credential. Failed creates that involved the control plane carry an X-Control-Plane-Request-ID response header for support correlation.
Attach the WebSocket at stream_url within 30 seconds — unattached sessions expire. See Streaming.
Delete a session
DELETE /v1/sessions/{session_id} aborts and removes the session, returning 204 No Content.