Control plane API
The hosted API at gateway.speko.dev that the sidecar consumes in managed mode.
The gateway talks to Speko's control plane at https://gateway.speko.dev in managed mode. You normally never call these endpoints yourself — the sidecar does — but the contract is documented here for transparency and for anyone implementing the protocol independently.
Conventions
- Auth is
Authorization: Bearer <SPEKO_API_KEY>, except where noted. - Every plan-related POST sends
Idempotency-KeyandSpeko-Protocol-Revision: 3(exact match required; mismatches return400 unsupported_protocol_revision). - Bodies are JSON, capped at 1 MiB, with unknown fields rejected.
- Every response carries an
X-Request-IDheader (cp_...) — quote it in support requests. - The error envelope is minimal:
{"error":{"code":"..."}}. Note this differs from the relay envelope.
Endpoints
| Method + path | Auth | Purpose |
|---|---|---|
GET /healthz, GET /readyz | none | health |
GET /.well-known/jwks.json | none | session-plan signing keys |
GET /.well-known/relay-jwks.json | none | relay-plan signing keys (separate key set by design) |
POST /v1/session-plans | API key | mint one signed session plan |
POST /v1/session-plan-batches | API key | {"count": N, "plan": {...}} → up to 16 plans (warm-pool prefetch) |
POST /v1/sessions/{session_id}/fallback-plans | API key or plan token | exchange a failed attempt for a plan on a backup provider |
PUT /v1/runtime-instances/{instance_id} | API key | instance heartbeat |
DELETE /v1/runtime-instances/{instance_id} | API key | mark instance offline |
POST /v1/runtime-events | plan telemetry token | authenticated content-free telemetry |
POST /v1/anonymous-runtime-events | none allowed | BYOK anonymous telemetry; a request with an Authorization header is rejected |
POST /v1/turn-events | API key | authenticated conversation-profiler markers |
POST /v1/anonymous-turn-events | none allowed | BYOK profiler markers without account linkage; authorization headers are rejected |
Plan issuance errors
| Status | Code |
|---|---|
| 401 | authentication_failed |
| 402 | credit_exhausted |
| 403 | launches_disabled, provider_not_entitled |
| 409 | idempotency_conflict, idempotency_in_progress |
| 422 | no_eligible_route |
| 429 | quota_exhausted |
| 503 | service_unavailable |
The control plane and the relay name credit exhaustion differently: credit_exhausted here, insufficient_credit on the relay. Both are HTTP 402.
What a signed session plan contains
The plan is a JWS (typ: speko.session-plan+jws, algorithm EdDSA or RS256, audience speko-runtime) whose payload binds:
plan_id,session_id,attempt_id, and an expiry (minutes)- the route: provider, model, optional voice and region, adapter, transport, endpoint, and — on managed routes — a short-lived provider credential
- the reservation: metering unit, authorized units, a fixed provider-direct deadline, and concurrency reservation
- the telemetry destination and session-scoped token
- an optional fallback exchange URL
requirements: protocolspeko.voice.v0, revision exactly3
The gateway verifies signature, kid against the JWKS, issuer, audience, expiry, and single-use jti before opening the provider connection. Fallback exchanges are always forced to the configured control-plane origin, even if a plan says otherwise. Full trust details in Trust and signing.
Provider-direct plan deadlines are fixed and enforced locally. There is no mid-call renewal endpoint. The hosted Relay uses a separate renewable lease contract for its long-lived streams.