Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
twilio avatar

Twilio Voice Outbound Calls

  • 95 installs
  • 26 repo stars
  • Updated July 29, 2026
  • twilio/ai

Skill to create outbound phone calls via Twilio REST API with AMD, recording, conferencing, and webhook-based call control for sales dialers and automated voice systems.

About

This skill enables developers to build outbound voice calling systems using Twilio's Programmable Voice REST API. It covers core capabilities including basic call creation with TwiML, answering machine detection (AMD) for sales dialers, conference-based agent bridging, call recording, and status tracking. Developers can implement dynamic call handling via webhook URLs, track call state transitions, and integrate AMD callbacks for intelligent call routing. The skill includes TCPA compliance guidance (consent, quiet hours, Do Not Call lists) and patterns for both synchronous inline TwiML and asynchronous webhook-based call control. Supports Python and Node.js SDKs with production-ready examples for live-agent connection and voicemail handling.

  • Answering Machine Detection (AMD) for sales dialers with async callbacks and tunable speech thresholds
  • Conference-based agent bridging with whisper, barge-in, and hold capabilities via TwiML
  • Webhook-based dynamic call handling for flexible, real-time TwiML routing
  • Call recording with status callbacks and compliance-ready TCPA guidance
  • Status tracking through full call lifecycle (queued, ringing, in-progress, completed)

Twilio Voice Outbound Calls by the numbers

  • 95 all-time installs (skills.sh)
  • +9 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #3,008 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/twilio/ai --skill twilio-voice-outbound-calls

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs95
repo stars26
Last updatedJuly 29, 2026
Repositorytwilio/ai

What it does

Make outbound phone calls via Twilio's voice platform with AMD, recording, conferencing, and agent bridging for sales dialers and automated systems.

Who is it for?

Sales dialers, automated notification systems, customer support callback workflows, compliance-heavy voice applications, agent routing platforms.

Skip if: Inbound call handling (use twilio-voice-twiml), real-time AI conversation (use twilio-voice-conversation-relay), SMS or messaging tasks.

When should I use this skill?

User requests outbound calling, asks about AMD, needs call recording, wants to build sales dialer, requests conference call bridging, needs call status tracking.

What you get

Build production voice applications with live-agent connection, AMD-filtered dialing, conference bridging, and full call lifecycle monitoring.

Files

SKILL.mdMarkdownGitHub ↗

Overview

Agent safety: Before placing an outbound call, always confirm the recipient number and intent with the user. Outbound calls are irreversible and may incur charges. For automated systems, implement TCPA compliance: obtain prior express consent, respect quiet hours (8 AM–9 PM recipient local time), and maintain a Do Not Call list.

Every outbound call requires a from Twilio number, a to recipient, and TwiML instructions that define what happens when the call is answered — either as a webhook URL or inline.

---

Voice Platform Capabilities

Outbound calls go beyond basic calls.create(). Here's what you can build:

CapabilityHowWhen to use
Basic outbound callcalls.create() with TwiML or webhook URLAny outbound call — see Quickstart below
Answering Machine Detection (AMD)machineDetection parameter on calls.create()Sales dialers, call campaigns — filter voicemail from humans
Conference-based agent bridging<Dial><Conference> in TwiMLConnect agents to live prospects with whisper, barge, hold
SIP TrunkingElastic SIP TrunkingBring your own carrier for outbound calls — cost reduction at scale
Call Recordingrecord=True on calls.create() or <Record> verbCompliance, QA, training
Voice InsightsAutomatic per-call metricsCall quality monitoring — latency, jitter, packet loss, answer rates
AI Voice AgentsConversationRelay + LLMReal-time speech recognition → LLM → TTS for conversational AI

For TwiML verbs (Say, Gather, Dial, Record, Conference, Pay), see twilio-voice-twiml. For AI voice agents, see twilio-voice-conversation-relay.

---

Prerequisites

  • Twilio account with a voice-capable phone number

— New to Twilio? See twilio-account-setup for signup, getting a number, and trial limitations — Trial accounts can only call verified numbers

  • Environment variables:
  • TWILIO_ACCOUNT_SID
  • TWILIO_AUTH_TOKEN

— See twilio-iam-auth-setup for credential setup and best practices

  • SDK: pip install twilio / npm install twilio

---

Quickstart

Python

import os
from twilio.rest import Client

client = Client(os.environ["TWILIO_ACCOUNT_SID"], os.environ["TWILIO_AUTH_TOKEN"])

call = client.calls.create(
    from_="+15017122661",    # Your Twilio number (E.164)
    to="+15558675310",       # Recipient (E.164)
    twiml="<Response><Say>Your order has shipped. Goodbye.</Say></Response>"
)

print(call.sid)     # CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
print(call.status)  # queued | ringing | in-progress | completed | failed

Node.js

const twilio = require("twilio");
const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);

const call = await client.calls.create({
    from: "+15017122661",
    to: "+15558675310",
    twiml: "<Response><Say>Your order has shipped. Goodbye.</Say></Response>",
});

console.log(call.sid);
console.log(call.status);

---

Key Patterns

Use a Webhook URL for Dynamic Call Handling

Pass a url instead of inline twiml — Twilio POSTs to your server when the call connects and executes the TwiML you return.

Python

call = client.calls.create(
    from_="+15017122661",
    to="+15558675310",
    url="https://yourapp.com/twiml/welcome"
)

Node.js

const call = await client.calls.create({
    from: "+15017122661",
    to: "+15558675310",
    url: "https://yourapp.com/twiml/welcome",
});

Python (Flask) — TwiML webhook handler

from flask import Flask
from twilio.twiml.voice_response import VoiceResponse

app = Flask(__name__)

@app.route("/twiml/welcome", methods=["POST"])
def welcome():
    response = VoiceResponse()
    response.say("Hello! Press 1 to hear your account balance.")
    response.gather(num_digits=1, action="/twiml/handle-input")
    return str(response)

Node.js (Express) — TwiML webhook handler

const { VoiceResponse } = require("twilio").twiml;

app.post("/twiml/welcome", (req, res) => {
    const response = new VoiceResponse();
    response.say("Hello! Press 1 to hear your account balance.");
    response.gather({ numDigits: 1, action: "/twiml/handle-input" });
    res.type("text/xml").send(response.toString());
});

For all TwiML verbs (Say, Gather, Dial, Record, Conference), see twilio-voice-twiml.

Track Call Status

Python

call = client.calls.create(
    from_="+15017122661",
    to="+15558675310",
    url="https://yourapp.com/twiml/welcome",
    status_callback="https://yourapp.com/call-status",
    status_callback_method="POST"
)

Node.js

const call = await client.calls.create({
    from: "+15017122661",
    to: "+15558675310",
    url: "https://yourapp.com/twiml/welcome",
    statusCallback: "https://yourapp.com/call-status",
    statusCallbackMethod: "POST",
});

Status transitions: queued → ringing → in-progress → completed (or failed/busy/no-answer).

Record a Call

Python

call = client.calls.create(
    from_="+15017122661",
    to="+15558675310",
    url="https://yourapp.com/twiml/welcome",
    record=True,
    recording_status_callback="https://yourapp.com/recording-ready"
)

Node.js

const call = await client.calls.create({
    from: "+15017122661",
    to: "+15558675310",
    url: "https://yourapp.com/twiml/welcome",
    record: true,
    recordingStatusCallback: "https://yourapp.com/recording-ready",
});

Recordings accessible at https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Recordings.

---

Answering Machine Detection (AMD)

Detect whether a human or voicemail answers before connecting an agent or leaving a message. Two modes:

ModeBehaviorBest for
EnableReturns result immediately when human/machine first detectedSales dialers — connect agent to humans ASAP
DetectMessageEndWaits for voicemail greeting to finish (beep/silence)Leaving voicemail — wait for beep, then play/record message

Python — Sales dialer (connect agents to live answers only)

call = client.calls.create(
    from_="+15017122661",
    to="+15558675310",
    url="https://yourapp.com/handle-answer",
    machine_detection="Enable",  # Immediate detection — use for live-agent connect
    async_amd=True,              # Non-blocking — call connects while AMD analyzes
    async_amd_status_callback="https://yourapp.com/amd-result",
    async_amd_status_callback_method="POST"
)

Node.js

const call = await client.calls.create({
    from: "+15017122661",
    to: "+15558675310",
    url: "https://yourapp.com/handle-answer",
    machineDetection: "Enable",
    asyncAmd: true,
    asyncAmdStatusCallback: "https://yourapp.com/amd-result",
    asyncAmdStatusCallbackMethod: "POST",
});

AMD webhook delivers `AnsweredBy` parameter:

ValueMeaningAction
humanLive person detectedConnect to agent
machine_startMachine detected, greeting still playingHang up or wait
machine_end_beepVoicemail beep heardLeave message
machine_end_silenceSilence after greetingLeave message
faxFax tone detectedHang up
unknownCould not determineTreat as human or retry

Conference-based agent bridging (production pattern for sales dialers):

# In /handle-answer webhook — when AMD says "human":
response = VoiceResponse()
dial = response.dial()
dial.conference(
    f"Sales-{call_sid}",
    start_conference_on_enter=False,  # Prospect waits for agent
    end_conference_on_exit=True
)

# Separately, dial agent into same conference:
client.calls.create(
    from_="+15017122661",
    to=agent_number,
    twiml=f'<Response><Dial><Conference startConferenceOnEnter="true">Sales-{call_sid}</Conference></Dial></Response>'
)

This pattern gives you call control (whisper to agent before connecting, supervisor barge-in, hold) that direct <Dial> does not.

Cost: AMD adds ~$0.0075 per call to standard voice pricing.

---

Response Fields

FieldDescription
sidCall identifier (CA...)
statusqueued, ringing, in-progress, completed, failed, busy, no-answer
durationLength in seconds (after completion)
priceCost (populated after completion)

---

Common Errors

CodeMeaningFix
21211Invalid to numberValidate E.164 format
13224Invalid TwiML at webhook URLValidate TwiML response from your server
13225TwiML URL returned non-200 statusFix your webhook endpoint

---

CANNOT

  • Cannot use a private TwiML URL — Must be publicly accessible. Use ngrok for local development only; deploy to a cloud provider for production.
  • Cannot exceed ~4,096 characters in inline `twiml` parameter — Use a TwiML URL for longer responses
  • Cannot call unverified numbers on trial accounts — Upgrade to paid or verify recipient numbers first
  • AMD accuracy is ~85-90% — Expect some false positives/negatives. Tune machineDetectionSpeechThreshold (default 2400ms) based on your results.
  • AMD adds latencyEnable mode returns results faster but may misclassify short greetings. DetectMessageEnd is more accurate but adds seconds before your app can act.
  • Cannot use AMD with SIP Trunking — AMD is only available on calls made via the Calls API

---

Next Steps

  • TwiML verb reference (Say, Gather, Dial, Record, Conference, Pay): twilio-voice-twiml
  • AI voice agents with real-time speech/LLM: twilio-voice-conversation-relay
  • Improve answer rates (Branded Calling, STIR/SHAKEN): twilio-numbers-senders

Related skills

Backend & APIsagentsautomation

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.