404. Move every Omni client to:
Migration checklist
1. Replace the URL and query parameters
session_label is an opaque, optional tag. It can also be a managed Agent
profile id. Values must be no more than 256 characters and safe to place in an
HTTP header. Do not send agent, agent_id, access_token, or model to
/v1/omni. The route rejects agent and agent_id with
400 unsupported_parameter; access_token is not an auth mechanism; model
is outside the canonical Omni contract.
Keep format and rate explicit. Use pcm16 and 24000 for a browser or
24 kHz audio pipeline. Use the actual negotiated rate if your telephony
pipeline is 16 kHz or 8 kHz.
2. Use a supported auth mechanism
For browser clients, send the API key as a WebSocket subprotocol:api_key to the URL. Do
not place the key in access_token or another query parameter. The key needs
the omni:session scope.
3. Send configure after the socket opens
Send one 0x03-prefixed binary control frame. Its JSON body is keyed on
type, not event:
session_label, you can omit fields
already stored on that profile. An inline configure value overrides the
stored value for the session.
4. Keep native Omni binary framing
Every WebSocket message uses a one-byte type prefix:
Prefix every caller-audio chunk with
0x01. Prefix client controls such as
configure, dtmf, and tool_result with 0x03. Client controls use a
type key. Server control payloads use an event key; transcript payloads are
plain text.
Error and close behavior
Handshake failures happen before a WebSocket session exists:
After a successful upgrade, handle these WebSocket closes:
Do not rely on every auth or parameter failure arriving as a WebSocket close.
The canonical edge can reject the HTTP upgrade first. A reconnect starts a new
session and requires a fresh
configure frame.
Troubleshooting
404during connect: the URL still points at the discontinued route.400 unsupported_parameter: copy anagentoragent_idvalue intosession_label, then remove the old parameter.- The socket opens but the agent hears nothing: caller audio is missing the
0x01prefix, is not PCM16 little-endian, or does not match the URLrate. - The socket opens but the persona is ignored: the outbound configure body
uses
event: "configure"instead oftype: "configure", or it was sent as text instead of a0x03binary frame. - Control data sounds like an audio glitch: demultiplex
0x02transcript and0x03control frames instead of sending them to audio playback. 401or4401: use a valid PyAI key through a supported auth mechanism.403or4403: add theomni:sessionscope to the key.