# PyAI API > Telephony-native Voice AI behind one bearer key. Products: Hear > (speech-to-text), Speak (text-to-speech + cloning), Cue (streaming turn > detection + knowledge-base context for your own pipeline), and Omni (agentic > full-duplex voice grounded in your knowledge bases and tools); Agents (managed > Omni) is coming soon. OpenAI-compatible REST at https://api.pyai.com/v1. Keys > are self-validating signed tokens that work on every surface the instant they > are created — treat them as opaque strings and never parse them. ## Start here - OpenAPI spec: https://api.pyai.com/openapi.json (machine-readable contract, source of truth). - API docs: https://api.pyai.com/docs (human reference with quickstarts). ## Authentication - Header: `Authorization: Bearer pyai_live_...` (alias `x-api-key`). - Environments: `pyai_live_...` (production), `pyai_test_...` (sandbox). - WebSocket: subprotocol `Sec-WebSocket-Protocol: pyai-key.pyai_live_...` (or `?api_key=...` server-side). - Keys are opaque (<=512 chars). Do not parse or decode. No activation/propagation delay. ## Endpoints - POST /v1/audio/transcriptions — speech-to-text, Hear (scope hear:transcribe). - GET /v1/audio/transcriptions/stream — streaming speech-to-text over WebSocket, eager partials (scope hear:stream); with knowledge-base grounding enabled this is Cue (turn detection + KB context). - POST /v1/audio/speech — text-to-speech, Speak (scope voice:synthesize). - GET /v1/voices, GET /v1/voices/{id} — voice catalog (any active key). - GET/POST /v1/voice/clones — voice cloning (scope voice:clone). - GET /v1/models — model catalog (any active key). - POST/GET /v1/transcription/jobs — async batch STT (scopes hear:transcribe + transcribe:jobs). - Realtime WebSocket — Omni (native): wss://api.pyai.com/v1/omni?agent_id= (scope omni:session). OpenAI-realtime-compat alias: /v1/realtime?model=pyai-omni-realtime. The older /v2/omni/chat URL is deprecated but still works. ## Errors Data-plane errors use the OpenAI shape { error: { message, type, code, param } }. Branch on error.code: - unauthorized (401), forbidden (403): auth/scope — do not retry. - credit_exhausted / key_budget_exceeded / insufficient_quota (402): billing — add credit or upgrade. - rate_limit_exceeded / concurrency_limit_exceeded / daily_cap_exceeded (429): back off, honor Retry-After. - invalid_agent_id (400): the `agent_id` on a realtime/Omni connect URL is malformed (control chars or too long). A first-call 402 credit_exhausted on a brand-new key is the billing gate, not a broken key.