make_call — place an outbound voice call
Pass to + a prompt and the assistant will speak it; the recipient's reply is recorded for up to 60 seconds by default. Or pass raw twiml for full control. Inline TwiML means no public webhook required.
Parameters
| Field | Type | Description |
|---|---|---|
| to required | string | E.164 destination number, e.g. +15555550100. |
| prompt optional | string | What the assistant should say when the recipient picks up. If record isn't false, a recording prompt is appended. |
| closing_message optional | string | Final line spoken before hangup. |
| twiml optional | string | Inline TwiML XML to use instead of the prompt/record flow. If set, prompt is ignored. |
| url optional | string | Public URL Twilio fetches for TwiML. Use only for stateful flows. |
| record optional | boolean | Record the recipient's reply. Default true. Ignored when twiml or url is supplied. |
| voice optional | string | Twilio TTS voice. See voices. Default Polly.Joanna-Neural. |
| language optional | string | Locale tag matching the voice, e.g. en-US, ar-EG. |
| max_recording_seconds optional | integer | Default 60. Max 14400. |
| machine_detection optional | enum | Enable · DetectMessageEnd · none. Default Enable. |
| status_callback optional | string | Public URL Twilio POSTs to as the call progresses. |
Example
// In your AI host's chat: "use crixin voice to call +15555550100 and ask in Egyptian Arabic what time their basketball court opens; record their reply for 60 seconds." // What the agent calls: make_call({ to: "+15555550100", prompt: "السلام عليكم، هل ممكن تقولولي إيه مواعيد ملعب كرة السلة عندكم؟", voice: "Polly.Hala-Neural", language: "ar-EG", max_recording_seconds: 60 }) // Returns: { "sid": "CA94e1d8…3a02", "status": "queued", "to": "+15555550100", "from": "+15555550100", "direction": "outbound-api", "start_time": null }
get_call — look up one call by SID
Returns status, duration, price, start/end timestamps. Useful right after make_call to poll until the call moves to completed.
| Field | Type | Description |
|---|---|---|
| call_sid required | string | The SID returned by make_call, e.g. CA94e1d8…. |
get_call({ call_sid: "CA94e1d8…3a02" })
// → status: 'completed', duration: '47', price: '-0.0085', price_unit: 'USD'
list_calls — recent call history
Filter by destination, source, status, or start window.
| Field | Type | Description |
|---|---|---|
| to optional | string | E.164 filter on the called number. |
| from optional | string | E.164 filter on the calling number. |
| status optional | enum | queued, ringing, in-progress, completed, busy, failed, no-answer, canceled. |
| start_time_after optional | string | ISO 8601 timestamp. |
| page_size optional | integer | 1–1000. Default 50. |
list_calls({
status: "completed",
start_time_after: "2026-05-01T00:00:00Z",
page_size: 100
})
list_recordings — recordings attached to a call
Returns SIDs, durations, and direct media URLs. The media URLs require your Twilio auth header to fetch — they're not public.
list_recordings({ call_sid: "CA94e1d8…3a02" })
// →
[{
sid: "RE5b8c…",
call_sid: "CA94e1d8…3a02",
duration: "47",
status: "completed",
media_url: "https://api.twilio.com/.../Recordings/RE5b8c….mp3"
}]
transcribe_call — Deepgram-powered transcription
Pulls the audio and runs it through Deepgram. 30+ languages including Arabic, Spanish, Portuguese, Mandarin. Returns transcript, confidence, word-level timestamps, and detected language. Requires DEEPGRAM_API_KEY in env.
| Field | Type | Description |
|---|---|---|
| recording_sid required | string | From list_recordings, e.g. RE5b8c…. |
| language optional | string | ISO 639-1 code: ar, en, es, etc. Pass auto to detect. |
| model optional | string | Deepgram model. Default nova-2. |
| diarize optional | boolean | Detect distinct speakers. Adds latency. |
transcribe_call({
recording_sid: "RE5b8c…",
language: "ar"
})
// →
{
recording_sid: "RE5b8c…",
language: "ar",
duration_seconds: 47,
transcript: "أهلاً، الملعب بيفتح الساعة سبعة الصبح وبيقفل الساعة عشرة بالليل…",
confidence: 0.91,
word_count: 38
}
send_sms — SMS / MMS
Optional messaging_service_sid for sticky-sender behavior across countries; optional media_url for MMS attachments.
| Field | Type | Description |
|---|---|---|
| to required | string | E.164. |
| body required | string | SMS text. Auto-segments past 160 chars. |
| messaging_service_sid optional | string | Use a Messaging Service for routing. |
| media_url optional | string | Image / PDF URL for MMS. |
| status_callback optional | string | Delivery status callback URL. |
send_sms({
to: "+15555550100",
body: "Reminder: 3pm appointment at Mansoura Stadium basketball court."
})
TTS voices — neural + standard
Twilio routes the voice parameter to Amazon Polly or Google TTS. Pick a neural voice when available — they're noticeably more natural.
| Voice | Language | Notes |
|---|---|---|
| Polly.Joanna-Neural | en-US | Default. Female, neural. |
| Polly.Matthew-Neural | en-US | Male, neural. |
| Polly.Hala-Neural | ar-EG | Egyptian Arabic, neural. Strong for Cairo/Mansoura/Alexandria. |
| Polly.Zeina | ar | Modern Standard Arabic. |
| Polly.Lucia-Neural | es-ES | Castilian Spanish. |
| Polly.Camila-Neural | pt-BR | Brazilian Portuguese. |
| Google.en-US-Wavenet-D | en-US | Google Wavenet, male. |
Inline TwiML — full control without webhooks
Pass raw TwiML XML in the twiml parameter when the prompt/record flow isn't enough — multi-step menus, DTMF input, conferencing, etc.
make_call({
to: "+15555550100",
twiml: `<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say voice="Polly.Joanna-Neural">Press 1 for hours, 2 for prices.</Say>
<Gather numDigits="1" action="https://example.com/menu">
<Say>Waiting...</Say>
</Gather>
</Response>`
})
For multi-step flows you'll need a public callback (action="…"). For single-shot prompts, the built-in prompt + record covers most use cases.
Error handling — what goes wrong, and why
Every tool returns either a JSON payload or a structured MCP error with isError: true. The error message is the underlying Twilio (or Deepgram) error verbatim — easy to grep, easy to retry.
// Common shapes: "Error: TwilioApiError: POST /Calls.json failed: { "code": 21211, "message": "Invalid 'To' Phone Number" }" "Error: Deepgram transcribe failed (401): Invalid credentials" "Error: Missing TWILIO_ACCOUNT_SID. Set it in your environment or Doppler."