Twilio Voice Twiml

作者 twilio8aba46fb65dc無授權條款收錄於 2026年10月8日更新於 2026年10月8日

Build voice call logic using TwiML (Twilio Markup Language). Covers the core verbs (Say, Play, Gather, Dial, Record, Conference), generating TwiML with Python and Node.js SDKs, and a complete inbound call IVR example. Use this skill to define call behavior for inbound or outbound calls.

AI 產生的概覽

使用 TwiML 建構 Twilio 語音通話邏輯,涵蓋核心動詞、SDK 產生方式和 IVR 範例。

功能
此技能說明如何使用 TwiML(Twilio 在通話期間執行的 XML)定義來電與去電的通話行為。內容記錄 Say、Play、Gather、Dial、Record、Conference 和 Pay 等核心動詞,並提供 Python 與 Node.js SDK 範例以及完整的來電 IVR 流程。此外也涵蓋 webhook 託管、請求之間的無狀態處理、監控、請求參數和已知限制。
適用情境
適用於實作從 webhook 傳回 TwiML 的通話處理邏輯,例如 IVR 選單、來電轉接、語音留言或會議設定。也適合使用 Twilio Python 或 Node.js SDK 以程式方式產生 TwiML。
執行需求
需要具備語音功能的電話號碼的 Twilio 帳戶、可公開存取並傳回 text/xml 的 HTTPS webhook 端點,以及可選地透過 pip 或 npm 安裝的 Twilio SDK。此技能不含指令碼,僅為說明文件。

Overview

TwiML is XML that Twilio executes during a call. Your server returns a TwiML document in response to a Twilio webhook POST, and Twilio executes it.

Caller → Twilio → POST to your webhook → Your server returns TwiML → Twilio executes it

Prerequisites

  • Twilio account with a voice-capable phone number — New to Twilio? See twilio-account-setup
  • Webhook endpoint returning TwiML with Content-Type: text/xml
  • SDK (for programmatic generation): pip install twilio / npm install twilio

Quickstart

A minimal inbound call handler that greets the caller and presents a menu:

Python (Flask)

python
from flask import Flask, requestfrom twilio.twiml.voice_response import VoiceResponse
app = Flask(__name__)
@app.route("/voice", methods=["POST"])def handle_call():    response = VoiceResponse()    gather = response.gather(num_digits=1, action="/menu-choice")    gather.say("Welcome to Acme. Press 1 for sales, 2 for support.")    response.redirect("/voice")  # Loop if no input    return str(response)
@app.route("/menu-choice", methods=["POST"])def menu_choice():    digit = request.form.get("Digits")    response = VoiceResponse()    if digit == "1":        response.dial("+15551234567")    elif digit == "2":        response.say("Connecting to support.")        response.dial("+15559876543")    else:        response.say("Invalid option.")        response.redirect("/voice")    return str(response)

Node.js (Express)

node
const { VoiceResponse } = require("twilio").twiml;
app.post("/voice", (req, res) => {    const response = new VoiceResponse();    const gather = response.gather({ numDigits: 1, action: "/menu-choice" });    gather.say("Welcome. Press 1 for sales, 2 for support.");    response.redirect("/voice");    res.type("text/xml").send(response.toString());});
app.post("/menu-choice", (req, res) => {    const digit = req.body.Digits;    const response = new VoiceResponse();    if (digit === "1") response.dial("+15551234567");    else response.say("Invalid option.").redirect("/voice");    res.type("text/xml").send(response.toString());});

Core Verbs

Say — Text-to-speech

Python

python
from twilio.twiml.voice_response import VoiceResponse
response = VoiceResponse()response.say("Your appointment is confirmed.", voice="alice", language="en-US")

Node.js

node
const { VoiceResponse } = require("twilio").twiml;const response = new VoiceResponse();response.say({ voice: "alice", language: "en-US" }, "Your appointment is confirmed.");

Voices: alice (default), man, woman, or Polly/Google TTS (e.g. Polly.Joanna).

Gather — Collect keypad input or speech

Python

python
response = VoiceResponse()gather = response.gather(num_digits=1, action="/handle-input", method="POST")gather.say("Press 1 for sales, press 2 for support.")response.say("We did not receive your input.")  # Fallback if no input

Node.js

node
const gather = response.gather({ numDigits: 1, action: "/handle-input", method: "POST" });gather.say("Press 1 for sales, press 2 for support.");response.say("We did not receive your input.");

Twilio POSTs collected digits to action as Digits parameter.

Play — Play an audio file

Python

python
response = VoiceResponse()response.play("https://example.com/audio/greeting.mp3")

Node.js

node
const response = new VoiceResponse();response.play("https://example.com/audio/greeting.mp3");

Supported formats: MP3, WAV. URL must be publicly accessible.

Dial — Connect to another number

Python

python
from twilio.twiml.voice_response import Dial
response = VoiceResponse()dial = Dial(action="/dial-complete")dial.number("+15558675310")response.append(dial)

Node.js

node
const dial = response.dial({ action: "/dial-complete" });dial.number("+15558675310");

Record — Capture caller audio

Python

python
response = VoiceResponse()response.say("Leave a message after the beep.")response.record(    action="/recording-complete",    max_length=60,    transcribe=True,    transcribe_callback="/transcription-ready")

Node.js

node
const response = new VoiceResponse();response.say("Leave a message after the beep.");response.record({    action: "/recording-complete",    maxLength: 60,    transcribe: true,    transcribeCallback: "/transcription-ready",});

Voicemail — Record a message when no one answers

Use <Dial> with action URL + <Record> in the action handler. When the dial times out or the callee is busy, the action URL serves TwiML with <Record>.

Python

python
# Primary TwiML — try to connect the callresponse = VoiceResponse()dial = Dial(action="/voicemail", timeout=20)  # 20 seconds before voicemaildial.number("+15558675310")response.append(dial)
# /voicemail handler — plays if no answerdef voicemail_handler(request):    response = VoiceResponse()    response.say("We missed your call. Please leave a message after the beep.")    response.record(        action="/recording-complete",        max_length=120,        transcribe=True,        transcribe_callback="/transcription-ready",        play_beep=True    )    response.say("We didn't receive a recording. Goodbye.")    return str(response)

Node.js

node
// Primary TwiML — try to connect the callconst response = new VoiceResponse();const dial = response.dial({ action: "/voicemail", timeout: 20 });dial.number("+15558675310");
// /voicemail handler — plays if no answerapp.post("/voicemail", (req, res) => {    const response = new VoiceResponse();    response.say("We missed your call. Please leave a message after the beep.");    response.record({        action: "/recording-complete",        maxLength: 120,        transcribe: true,        transcribeCallback: "/transcription-ready",        playBeep: true,    });    response.say("We didn't receive a recording. Goodbye.");    res.type("text/xml").send(response.toString());});

Important: <Record> captures the caller only (voicemail-style). It is NOT for recording two-party calls — see twilio-call-recordings for that.

Conference — Multi-party calls

Python

python
response = VoiceResponse()dial = response.dial()dial.conference(    "Daily Standup",    start_conference_on_enter=True,    end_conference_on_exit=True)

Node.js

node
const response = new VoiceResponse();const dial = response.dial();dial.conference("Daily Standup", {    startConferenceOnEnter: true,    endConferenceOnExit: true,});

Pay — PCI-compliant payment collection

Critical warnings:

  • Pay Connectors are Console-only — there is no REST API to create or manage connectors. Set up in Console > Voice > Pay Connectors before coding.
  • PCI Mode is IRREVERSIBLE once enabled on an account. Use a dedicated sub-account for payment calls.

Python

python
response = VoiceResponse()response.say("We'll now collect your payment.")pay = Pay(    payment_connector="stripe_connector",  # Name from Console setup    charge_amount="49.99",    currency="usd",    action="/payment-complete",    status_callback="/payment-status")response.append(pay)

Node.js

node
const response = new VoiceResponse();response.say("We'll now collect your payment.");response.pay({    paymentConnector: "stripe_connector",    chargeAmount: "49.99",    currency: "usd",    action: "/payment-complete",    statusCallback: "/payment-status",});

Supported processors: Stripe, Braintree, CardConnect. Card data routes directly to the processor — never touches your server.


Production Deployment

Webhook Hosting

For production, do NOT use ngrok. Deploy your TwiML server with HTTPS:

  • Requirement: Public HTTPS URL, responds within 15 seconds, returns Content-Type: text/xml
  • Options: Cloud Run, AWS Lambda + API Gateway, Railway, Render — any service with TLS and auto-scaling
  • Fallback URL: Configure in Console (Phone Numbers > Active Numbers > select number) for when your primary server is unreachable

State Between TwiML Requests

Each webhook request is stateless. To maintain conversation state across interactions:

  • URL query params: Pass state in action URLs — /next-step?language=es&dept=sales
  • Session store: Use Redis or a database keyed by CallSid
  • Do NOT use in-memory state — your server may scale to multiple instances

Monitoring

  • Status callbacks: Track call lifecycle events (statusCallback on the call or number config)
  • Voice Insights: Automatic quality metrics per call (Console > Monitor > Insights)
  • Debugger: Console > Monitor > Errors for TwiML parsing failures and webhook timeouts
  • Fallback URLs: Always configure a fallback TwiML URL — serves a graceful message if your primary endpoint fails

Webhook Request Parameters

ParameterDescription
CallSidUnique call identifier
FromCaller's number
ToCalled number
CallStatusCurrent status
Directioninbound or outbound-api

CANNOT

  • Cannot return TwiML without correct content type — Must use Content-Type: text/xml
  • Cannot exceed 15-second webhook response time — Twilio times out and falls back
  • Cannot exceed 4,096 characters in <Say> verb — Split longer text across multiple <Say> elements
  • Cannot create Pay Connectors via API — Pay Connectors are Console-only (Console > Voice > Pay Connectors). No REST API exists for connector management.
  • Cannot reverse PCI Mode — Once enabled on an account, PCI Mode is permanent and account-wide. Use a dedicated sub-account for payment calls.
  • Cannot use <Record> for two-party call recording — <Record> captures the caller only (voicemail-style). For dual-channel recording of both parties, use record=True on calls.create() or the Recordings API.

Next Steps

  • Place outbound calls (AMD, conferencing): twilio-voice-outbound-calls
  • AI voice agents with real-time speech/LLM: twilio-voice-conversation-relay

來源與署名

來源:twilio/ai位於skills/twilio/twilio-voice-twiml提交8aba46f

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架

更多來自 twilio/ai 的技能

Twilio Isv Sms Best Practices

twilio

給 ISV 的多租戶 Twilio SMS 建置指南,涵蓋 A2P 與免付費號碼註冊、子帳戶及常見陷阱。

Software Development2026年10月8日

Twilio Security Compliance Hipaa

twilio

指導為 HIPAA 合規設定 Twilio 帳戶,涵蓋 BAA、HIPAA 專案指定、合格服務及各產品要求。

Security2026年10月8日

Twilio Reliability Patterns

twilio

Handle rate limits, retries, and failures when building on Twilio at scale. Covers 429 exponential backoff with jitter, per-number throughput limits, StatusCallback resilience, thin-receiver pattern, and fallback chains. Use this skill whenever sending messages or making calls at volume, or when building production-grade Twilio integrations.

待分類2026年10月8日

Twilio Organizations Setup

twilio

Set up and manage Twilio Organizations for centralized account and user governance. Covers the Organization > Account > Subaccount hierarchy, roles (Owner/Admin/Standard), managed vs independent accounts, domain registration, SSO enforcement, SCIM provisioning, and Organization merging. Use this skill when managing multiple Twilio accounts or users across teams.

待分類2026年10月8日

Twilio Numbers Senders

twilio

指導在開發前選擇合適的 Twilio 號碼類型和傳送者,涵蓋合規計畫、輸送量和可用性。

Communication2026年10月8日

Twilio Notifications Alerts Advisor

twilio

為開發者提供 Twilio 交易型通知與告警架構的規劃建議,涵蓋管道、急迫性與備援方式。

Productivity & Workflow2026年10月8日