Put an assistant on a live call
POST/api/calls/:callId/ai
Runs the whole chain: resolve which assistant should answer, take one of its concurrent slots, deliver the EU AI Act Art. 50 disclosure, ask the session gate, build the provider's dial plan, and hand it to the media bridge.
A refusal is a 409 with a reason, not an error
Nothing about the request is wrong when an assistant may not open — the
answer is "not on this call, not right now". The reason is a
machine-readable key from VoiceAgentRefusalReason, and every one of
them has a translated sentence in the panel catalogue.
The disclosure is delivered BEFORE the model is dialled, never after
and never instead: a session whose disclosure could not be played is
refused with disclosure_unavailable and no provider socket is opened.
Today this works on PHONE LINES ONLY
No AI provider surveyed takes Opus at 48 kHz, and the media plane
refuses to resample 48 -> 8 kHz rather than do it badly. A WhatsApp or
Messenger call therefore cannot carry an assistant: it is refused with
ai_leg_wire_unsupported, and VoiceCapabilities.control.ai_leg is
false on those channels so the control is not drawn at all.
If the provider socket drops, we do NOT re-dial
The bridge parks the customer on hold music and reports
ai_stream_dropped; the leg moves to escalating and a PERSON is the
expected next actor. Re-dialling would be a NEW session with no history
(OpenAI's realtime WebSocket has no resumption), so the assistant would
greet the caller again mid-conversation — and would owe a second Art. 50
disclosure. Calling this endpoint again re-runs the whole chain
deliberately, disclosure included.
Request
Responses
- 200
- 403
- 404
- 409
The assistant is on the call.
Authenticated but not allowed.
Resource not found (or not visible to the current tenant).
The assistant may not open on this call. reason says which of the chain's checks refused.