Carrier
The carrier delivers the phone call to Patter. Patter supports Twilio, Telnyx, and Plivo. All three share inbound DTMF, call transfer, AMD, status callbacks, recording, voicemail drop, and cost tracking. Plivo additionally supports native DTMF send over the media WebSocket — a capability Twilio Media Streams lacks. You configure one carrier perPatter instance by passing an instance to the carrier= keyword argument. Each carrier class falls back to environment variables when constructor arguments are omitted.
Each carrier ships as both a flat alias (from getpatter import Twilio, Telnyx, Plivo) and a namespaced class (from getpatter.carriers import twilio → twilio.Carrier()). They are equivalent.
Twilio
Namespaced form:
serve(), Patter automatically sets the voice_url on the Twilio number to https://<webhook_url>/webhooks/twilio/voice via the Twilio REST API — no manual Console configuration needed.
Twilio trial account limitations
Twilio trial accounts apply a few platform-level restrictions that affect first-time testing. None of these are Patter limitations — they’re Twilio platform rules:- Verified Caller IDs required for outbound — trial accounts can only call numbers you’ve added under Phone Numbers › Verified Caller IDs in the Twilio Console. Verifying via the CLI is also restricted; do it from the Console.
- Trial announcement prepended on outbound calls — Twilio plays an English trial-account message before connecting the call to your agent; the callee has to press a key to continue.
- Trial caller-ID restrictions — the caller-ID shown to the recipient may be masked or labelled differently than your purchased number until the account is upgraded.
Signature verification
The Auth Token is also used to verify every Twilio webhook with HMAC-SHA1 against theX-Twilio-Signature header. Requests with invalid signatures are rejected with HTTP 403.
Telnyx
Namespaced form:
Signature verification
Whenpublic_key is set (or TELNYX_PUBLIC_KEY is present), every Telnyx webhook is verified with Ed25519. Requests older than 5 minutes are rejected (replay protection).
Plivo
Namespaced form:
serve(), Patter best-effort creates a Plivo Application bound to https://<webhook_url>/webhooks/plivo/voice and links it to your phone number via the Plivo REST API. Most production deployments pre-configure the Plivo Application in the console — pass manage_webhook=False on serve() to opt out.
Wire format and parity gains
- Audio: mulaw 8 kHz, pinned via the
<Stream contentType="audio/x-mulaw;rate=8000">answer XML. Plivo’s<Stream>element places the WSS URL as its text content (not aurl=attribute, as Twilio does). - Native DTMF send over the media WebSocket via
sendDTMF— a parity gain over Twilio Media Streams. - Voicemail drop uses Plivo’s live-call Speak API +
DELETE /Call/{uuid}/hangup. - AMD is async: Patter sets
machine_detection="true"+machine_detection_url=/webhooks/plivo/amdso human pickups don’t incur the detection-window latency. - Status callback: Patter wires
hangup_url=/webhooks/plivo/statuson outbound calls so no-answer / busy / failed transitions reach the dashboard before any media webhook fires.
Signature verification
The Auth Token doubles as the V3 webhook signature key. The V3 scheme is:- POST:
signed = url + sorted_post_params + "." + nonce— POST params sorted alphabetically by key (case-sensitive) and concatenated askey1value1key2value2…with no delimiters. - GET:
signed = url + "." + nonce— query parameters live in the URL already.
X-Plivo-Signature-V3 header alongside X-Plivo-Signature-V3-Nonce. The signature header may carry comma-separated values during key rotation; any matching value accepts. Requests with invalid signatures are rejected with HTTP 403.
Webhook Endpoints
The embedded server exposes these endpoints regardless of carrier choice:Outbound calls
Usephone.call(...) to place an outbound call on either carrier. Every keyword argument is snake_case:
machine_detectiondefaults toTrue. On Twilio Patter sendsMachineDetection=DetectMessageEnd+ Async AMD so there is no answer-latency penalty on human pickups. PassFalseto skip per-call AMD billing.ring_timeoutdefaults to25seconds. Pass60for legacy carrier-default parity, orNoneto omit the parameter entirely.- The AMD callback was renamed
on_machine→on_machine_detectionand now receives aMachineDetectionResult(not a raw dict).
What’s Next
STT
Speech-to-text providers.
LLM
Language model providers.
TTS
Text-to-speech providers.
Tunneling
Expose your local server publicly.

