Overview
stateset-voice is StateSet’s AI phone platform: a Rust/axum server that answers and places Twilio calls with realtime-model voice agents, plus browser web calls over the identical media pipeline. Tenants drive it through a versioned REST API (/api/v1/...) with a single tenant API key, or through
the bundled MCP server that wraps that API 1:1.
- Prod (default target):
https://api.voice.stateset.com(API docs also referencehttps://voice.stateset.com) - Local dev:
http://localhost:5050 - Auth:
Authorization: Bearer stsk_<tenant>_<key-id>_<secret>(tenant API key)
Two ways in
1. MCP server (mcp-server/, package @stateset/voice-mcp-server)
Thin, stateless stdio server; every tool is one REST call with the configured
key passed through as Bearer.
Wire into a client (
claude mcp add, or MCP config JSON). The package is not yet on npm; build it from the repository’s mcp-server/ directory:
initialize / notifications/initialized / tools/list
JSON-RPC lines into node dist/index.js (exact lines in
mcp-server/README.md). A tools/call with a bad key returns a clean
HTTP 401: Invalid tenant credentials — path works, key doesn’t.
2. Raw REST
Tool ↔ endpoint map
Not wrapped by MCP but in the REST API: voice sessions
(
/voice/sessions...), live-session supervisor actions
(monitor/whisper/barge/escalate/end on
/voice/sessions/{stream_sid}/actions/*), and translation calls
(POST /voice/translation-calls).
Agent config schema
Accepted keys: instructions, assistant_profile, realtime_model,
chat_model, voice, greeting, agent_name, tools[].
Unknown keys are rejected with a 400 — never silently dropped.
tools[] are customer functions fulfilled by YOUR backend: mid-call the
server POSTs {tool, arguments, call} to endpoint.url (HMAC
X-Webhook-Signature); the JSON reply is the tool result. Validation is
eager: POST-only, public-https URL, 250–10000 ms timeout, max 16 tools; names
colliding with built-in platform functions are ignored in favor of the
built-in.
Canonical flows
Agent → number → call → transcriptcreate_agentwithpublish: true(response includes agent + version UUIDs).upsert_phone_number{phone_number, direction: "inbound"|"outbound", agent_id}.make_call(orPOST /voice/calls) → returnscall_sid.list_call_logs {call_sid}→get_call_log {uuid}for full transcript + summary.
POST /voice/calls:
Idempotency-Keyheader — same key within 24 h replays the stored outcome instead of dialing again; a concurrent duplicate gets409(retry shortly). On a deployment without a database the header itself returns503— the server never silently places a duplicate call.configbody — transient inline agent config for this call only (mutually exclusive withagent_version_id).metadata(≤ 4 KB JSON) — persisted and inherited by retry children.machine_detection:off|enable|detect_message_end; retries viamax_attempts,retry_on: ["no_answer","busy"],retry_backoff_seconds.
create_web_call → short-lived
signed websocket_url + ready-to-send start_message (embedded
stream_token is the whole auth story), audio ulaw_8000 20 ms base64
frames, expires_at ~5 min — mint one per call. Requires server
STREAM_AUTH_SECRET. Full browser client + wire protocol:
docs/sdk-web.md in the repo.
Knowledge: upsert_knowledge_source → search_knowledge {query};
sources are deterministic low-latency fast answers used before broader search.
Gotchas
make_calldials a real phone. DNC and TCPA quiet-hours gates apply — quiet hours evaluated in the called party’s timezone (NANP); blocked calls return403(policy) or503.create_api_keyreturns the secret token exactly once; store it immediately.revoke_api_keyis irreversible.- Agents are versioned.
PATCH /voice/agents/{id}creates a new version; it’s not live unlesspublish: true(or published later). - Unknown/invalid agent config → 400, not silently ignored.
- Voice lag? Start at
get_call_latency(p50/p95), then per-callget_call_log. - Errors are
{ "ok": false, "error": "..." }; common: 400 validation, 401 auth, 403 policy block (DNC/quiet hours), 409 duplicate, 503 missing backend (no DB, noSTREAM_AUTH_SECRET, no Twilio creds).
Further reading
- Voice API reference — the 65 tenant endpoints
- Voice MCP server — the 24 tools
- Voice webhooks