Endpoint:
wss://api.pyai.com/v1/amd/stream (scope amd:detect).
Config: POST /v1/amd/config (scope amd:configure). Reads:
GET /v1/amd/calls, GET /v1/amd/calls/{id} (scope amd:read).
Billed per answered call, the first 5,000 answered calls/month are free,
then $0.004/call; free when bundled with PyAI telephony or Omni.The wedge: a zero-code Twilio migration
AMD speaks Twilio’s Media Streams protocol natively (start / media /
stop frames, G.711 μ-law 8 kHz base64), so a customer already on Twilio adds
one line of TwiML, no carrier change, no new SDK, to fork the call’s media
to PyAI:
<Stream> (the query string is stripped before connecting), so the key travels
as a <Parameter>: it arrives in the stream’s start frame and PyAI verifies
it before processing any audio. A connection that never presents a valid key is
closed within seconds. Your own server-side clients (not Twilio) can authenticate
at the handshake instead, with ?api_key= on the URL or the
Sec-WebSocket-Protocol: pyai-key.<API_KEY> subprotocol.
The decision
PyAI pushes anamd event mid-call (and to the per-call TwiML webhook, if
you set one) so a predictive dialer can route or drop instantly:
A
machine decision is further classified by subtype, voicemail, ivr,
screening (iPhone/Google Call Screen), or music (hold music). The subtype
is stored on the call record rather than pushed on the wire: read it back with
GET /v1/amd/calls/{id} (or on the amd.call.completed webhook below), where
answered_by is one of human, machine, voicemail, ivr, screening,
music, sit_invalid, unknown.
Webhooks
Two webhook paths, carrying different payloads:- Per-call, the TwiML
<Parameter name="webhook">. The moment the decision lands, PyAI POSTs the wire event above (the coarseanswered_byclass) to that URL, for that call only. - Account-wide,
webhook_urlinPOST /v1/amd/config. When the call completes, PyAI POSTs a signedamd.call.completedevent with the full call record, including the machine subtype inanswered_by:
The one dial: aggressiveness
AMD has a single operating-point dial, aggressiveness ∈ [0, 1], set per account
(POST /v1/amd/config) or per call (a TwiML <Parameter>):
- 0.0-0.25, human-safe (default). Never hang up on a person. For predictive
dialers with live agents; on the deadline it returns
unknown(let the agent listen) rather than risk a falsemachine. - 0.6-1.0, machine-aggressive. Fire
machinefast, for AI voicemail-drop bots.
machine (hang up on a prospect) is far
worse than a false human (waste a few agent-seconds), so you pick your point on
the curve instead of living with one fixed default.
Set it up with the SDK
Two ways to turn it on
- Twilio drop-in, the TwiML above. Keep your carrier and your code; the
answered_by_twiliofield speaks Twilio’s exact vocabulary. - Native, a flag on any call already running on PyAI telephony or Omni. Bundled AMD is included at no charge.
Billing
Billed per answered call (amd.calls): no-answers, busies, and failed calls
are free, the same basis as Twilio. The first 5,000 answered calls each month are
free (a self-serve “get started free” tier), then $0.004/answered call. AMD
bundled with PyAI telephony or Omni is included. A fast decision also means
fewer dead-air carrier seconds on every answered call.