Twilio API client and TwiML generator for comprehensive telecommunications services
XML markup language generation for controlling voice calls and messaging flows. Provides Python classes that generate TwiML XML for call routing, text-to-speech, user input collection, and message handling.
Create TwiML responses for voice calls with support for speech synthesis, call routing, user input collection, and call control.
class VoiceResponse:
"""Main class for generating voice TwiML responses"""
def __init__(self):
"""Initialize a new voice response"""
def say(
self,
message: str = None,
voice: str = None,
language: str = None,
loop: int = None
) -> Say:
"""
Text-to-speech synthesis.
Args:
message (str): Text to speak
voice (str): Voice to use ('man', 'woman', 'alice')
language (str): Language code (e.g., 'en-US', 'es-ES')
loop (int): Number of times to repeat
Returns:
Say: Say verb element
"""
def play(
self,
url: str = None,
loop: int = None,
digits: str = None
) -> Play:
"""
Play audio file from URL.
Args:
url (str): URL of audio file to play
loop (int): Number of times to repeat
digits (str): DTMF digits to send during playback
Returns:
Play: Play verb element
"""
def dial(
self,
number: str = None,
action: str = None,
method: str = None,
timeout: int = None,
hangup_on_star: bool = None,
time_limit: int = None,
caller_id: str = None,
record: str = None,
trim: str = None,
recording_status_callback: str = None,
recording_status_callback_method: str = None,
recording_status_callback_event: list = None,
answer_on_bridge: bool = None,
ring_tone: str = None,
recording_track: str = None,
sequential: bool = None
) -> Dial:
"""
Dial phone numbers, SIP addresses, or clients.
Args:
number (str): Phone number to dial
action (str): Webhook URL after dial completes
method (str): HTTP method for action URL
timeout (int): Ring timeout in seconds
hangup_on_star (bool): Hang up when caller presses *
time_limit (int): Maximum call duration in seconds
caller_id (str): Caller ID to display
record (str): Record the call ('record-from-answer')
Returns:
Dial: Dial verb element
"""
def gather(
self,
input: str = None,
action: str = None,
method: str = None,
timeout: int = None,
finish_on_key: str = None,
num_digits: int = None,
partial_result_callback: str = None,
partial_result_callback_method: str = None,
language: str = None,
hints: str = None,
barge_in: bool = None,
debug: bool = None,
action_on_empty_result: bool = None,
speech_timeout: str = None,
enhanced: bool = None,
speech_model: str = None,
profanity_filter: bool = None
) -> Gather:
"""
Collect user input via DTMF or speech.
Args:
input (str): Input type ('dtmf', 'speech', 'dtmf speech')
action (str): Webhook URL to send results
method (str): HTTP method for action URL
timeout (int): Input timeout in seconds
finish_on_key (str): Key to end input (default: #)
num_digits (int): Number of digits to collect
language (str): Speech recognition language
hints (str): Speech recognition hints
barge_in (bool): Allow input during nested verbs
Returns:
Gather: Gather verb element
"""
def record(
self,
action: str = None,
method: str = None,
timeout: int = None,
finish_on_key: str = None,
max_length: int = None,
play_beep: bool = None,
trim: str = None,
recording_status_callback: str = None,
recording_status_callback_method: str = None,
transcribe: bool = None,
transcribe_callback: str = None
) -> Record:
"""
Record caller's voice.
Args:
action (str): Webhook URL after recording
method (str): HTTP method for action URL
timeout (int): Silence timeout in seconds
finish_on_key (str): Key to stop recording
max_length (int): Maximum recording length in seconds
play_beep (bool): Play beep before recording
trim (str): Trim silence ('trim-silence')
transcribe (bool): Enable transcription
Returns:
Record: Record verb element
"""
def pause(self, length: int = None) -> Pause:
"""
Pause execution.
Args:
length (int): Pause duration in seconds
Returns:
Pause: Pause verb element
"""
def redirect(
self,
url: str = None,
method: str = None
) -> Redirect:
"""
Redirect to new TwiML URL.
Args:
url (str): New TwiML URL
method (str): HTTP method ('GET' or 'POST')
Returns:
Redirect: Redirect verb element
"""
def hangup(self) -> Hangup:
"""
End the call.
Returns:
Hangup: Hangup verb element
"""
def reject(self, reason: str = None) -> Reject:
"""
Reject incoming call.
Args:
reason (str): Rejection reason ('rejected', 'busy')
Returns:
Reject: Reject verb element
"""
def enqueue(
self,
name: str = None,
action: str = None,
method: str = None,
wait_url: str = None,
wait_url_method: str = None,
workflow_sid: str = None
) -> Enqueue:
"""
Place caller in queue.
Args:
name (str): Queue name
action (str): Webhook URL after dequeue
wait_url (str): TwiML URL while waiting
workflow_sid (str): TaskRouter workflow SID
Returns:
Enqueue: Enqueue verb element
"""
def leave(self) -> Leave:
"""
Leave current queue.
Returns:
Leave: Leave verb element
"""
def to_xml(self) -> str:
"""
Generate XML string.
Returns:
str: Complete TwiML XML document
"""
# Dial sub-elements
class Number:
"""Phone number to dial within <Dial>"""
def __init__(
self,
number: str,
send_digits: str = None,
url: str = None,
method: str = None,
status_callback_event: list = None,
status_callback: str = None,
status_callback_method: str = None,
byoc: str = None,
machine_detection: str = None,
machine_detection_timeout: int = None,
amd_status_callback: str = None,
amd_status_callback_method: str = None
): ...
class Conference:
"""Conference room within <Dial>"""
def __init__(
self,
name: str,
muted: bool = None,
beep: str = None,
start_conference_on_enter: bool = None,
end_conference_on_exit: bool = None,
wait_url: str = None,
wait_method: str = None,
max_participants: int = None,
record: str = None,
region: str = None,
whisper: str = None,
trim: str = None,
status_callback_event: list = None,
status_callback: str = None,
status_callback_method: str = None,
recording_status_callback: str = None,
recording_status_callback_method: str = None,
recording_status_callback_event: list = None,
event_callback_url: str = None,
jitter_buffer_size: str = None,
coach: str = None,
call_sid_to_coach: str = None
): ...
class Queue:
"""Queue within <Dial>"""
def __init__(
self,
name: str,
url: str = None,
method: str = None,
reservation_sid: str = None,
post_work_activity_sid: str = None
): ...
class Sip:
"""SIP address within <Dial>"""
def __init__(
self,
uri: str,
username: str = None,
password: str = None
): ...
class Client:
"""Twilio Client within <Dial>"""
def __init__(
self,
identity: str,
url: str = None,
method: str = None,
status_callback_event: list = None,
status_callback: str = None,
status_callback_method: str = None
): ...Voice TwiML examples:
from twilio.twiml.voice_response import VoiceResponse
# Basic text-to-speech
response = VoiceResponse()
response.say("Hello, welcome to our service!")
print(response)
# Output: <Response><Say>Hello, welcome to our service!</Say></Response>
# Play audio with loop
response = VoiceResponse()
response.play("https://example.com/music.mp3", loop=3)
# Collect DTMF input
response = VoiceResponse()
gather = response.gather(num_digits=4, action="/process-input", method="POST")
gather.say("Please enter your 4-digit PIN followed by the pound key")
response.say("We didn't receive any input. Goodbye!")
# Make outbound call
response = VoiceResponse()
dial = response.dial("+15559876543", timeout=30, caller_id="+15551234567")
# Conference call
response = VoiceResponse()
dial = response.dial()
dial.conference("My Conference Room",
start_conference_on_enter=True,
end_conference_on_exit=True)
# Record voicemail
response = VoiceResponse()
response.say("Please leave a message after the beep")
response.record(max_length=30,
action="/handle-recording",
finish_on_key="#")
# Call screening with gather
response = VoiceResponse()
gather = response.gather(num_digits=1, action="/screen-response")
gather.say("Press 1 to accept this call, press 2 to send to voicemail")
response.hangup()
# Complex call flow
response = VoiceResponse()
gather = response.gather(input="speech dtmf",
action="/handle-input",
speech_timeout="auto")
gather.say("Say or press a department: Sales, Support, or Billing")
response.redirect("/main-menu")Create TwiML responses for SMS/MMS message handling with support for replies and redirects.
class MessagingResponse:
"""Main class for generating messaging TwiML responses"""
def __init__(self):
"""Initialize a new messaging response"""
def message(
self,
body: str = None,
to: str = None,
from_: str = None,
action: str = None,
method: str = None,
status_callback: str = None
) -> Message:
"""
Send reply message.
Args:
body (str): Message text content
to (str): Recipient phone number
from_ (str): Sender phone number
action (str): Webhook URL after sending
method (str): HTTP method for action URL
status_callback (str): Delivery status webhook
Returns:
Message: Message element
"""
def redirect(
self,
url: str = None,
method: str = None
) -> Redirect:
"""
Redirect to new TwiML URL.
Args:
url (str): New TwiML URL
method (str): HTTP method ('GET' or 'POST')
Returns:
Redirect: Redirect element
"""
def to_xml(self) -> str:
"""
Generate XML string.
Returns:
str: Complete TwiML XML document
"""
class Message:
"""Message element for replies"""
def __init__(
self,
body: str = None,
to: str = None,
from_: str = None,
action: str = None,
method: str = None,
status_callback: str = None
): ...
def body(self, message: str) -> Body:
"""Set message body text"""
def media(self, url: str) -> Media:
"""Add media attachment"""
class Body:
"""Message body text"""
def __init__(self, message: str): ...
class Media:
"""Media attachment"""
def __init__(self, url: str): ...Messaging TwiML examples:
from twilio.twiml.messaging_response import MessagingResponse
# Simple reply
response = MessagingResponse()
response.message("Thanks for your message!")
print(response)
# Output: <Response><Message>Thanks for your message!</Message></Response>
# Reply with media
response = MessagingResponse()
message = response.message()
message.body("Here's the image you requested:")
message.media("https://example.com/image.jpg")
# Forward to another number
response = MessagingResponse()
response.message("Message forwarded", to="+15551234567")
# Auto-reply with redirect
response = MessagingResponse()
response.message("Processing your request...")
response.redirect("/process-message", method="POST")
# Conditional responses based on webhook data
response = MessagingResponse()
# This would typically be in a webhook handler
incoming_body = "HELP" # From webhook parameters
if incoming_body.upper() == "HELP":
response.message("Available commands: INFO, SUPPORT, STOP")
elif incoming_body.upper() == "STOP":
response.message("You have been unsubscribed.")
else:
response.message("Unknown command. Reply HELP for options.")Base functionality shared across voice and messaging TwiML generation.
class TwiML:
"""Base class for all TwiML responses"""
def __init__(self):
"""Initialize TwiML response"""
def append(self, twiml: 'TwiML') -> 'TwiML':
"""
Append another TwiML element.
Args:
twiml (TwiML): Element to append
Returns:
TwiML: Self for chaining
"""
def to_xml(self) -> str:
"""
Generate XML string representation.
Returns:
str: XML document string
"""
def __str__(self) -> str:
"""String representation returns XML"""
class GenericNode:
"""Generic XML element for custom TwiML"""
def __init__(
self,
name: str,
body: str = None,
**kwargs
):
"""
Create custom XML element.
Args:
name (str): XML element name
body (str): Element text content
**kwargs: Element attributes
"""Advanced TwiML usage:
from twilio.twiml.voice_response import VoiceResponse
from twilio.twiml import GenericNode
# Chaining TwiML elements
response = VoiceResponse()
response.say("Welcome").pause(1).say("Please hold")
# Using generic nodes for custom elements
response = VoiceResponse()
custom = GenericNode("CustomElement", "Custom content", attr="value")
response.append(custom)
# Building complex nested structures
response = VoiceResponse()
gather = response.gather(action="/process")
gather.say("Press 1 for sales")
gather.pause(1)
gather.say("Press 2 for support")
response.say("No input received")
response.hangup()
# Multiple dial targets
response = VoiceResponse()
dial = response.dial()
dial.number("+15551111111", status_callback="/call-progress")
dial.number("+15552222222", status_callback="/call-progress")
dial.client("alice")
# XML output customization
response = VoiceResponse()
response.say("Hello")
xml_string = response.to_xml()
print(xml_string) # Pretty-printed XMLCreate TwiML responses for fax transmission and reception handling.
class FaxResponse:
"""Main class for generating fax TwiML responses"""
def __init__(self):
"""Initialize a new fax response"""
def receive(
self,
action: str = None,
method: str = None,
media_type: str = None,
store_media: bool = None,
page_size: str = None
) -> Receive:
"""
Receive incoming fax transmission.
Args:
action (str): Webhook URL after fax reception
method (str): HTTP method for action URL
media_type (str): Media type ('application/pdf', 'image/tiff')
store_media (bool): Store received fax media
page_size (str): Page size for received fax
Returns:
Receive: Receive verb element
"""
def reject(self, reason: str = None) -> Reject:
"""
Reject incoming fax.
Args:
reason (str): Rejection reason
Returns:
Reject: Reject verb element
"""
def to_xml(self) -> str:
"""
Generate XML string.
Returns:
str: Complete TwiML XML document
"""
class Receive:
"""Fax receive element"""
def __init__(
self,
action: str = None,
method: str = None,
media_type: str = None,
store_media: bool = None,
page_size: str = None
): ...Fax TwiML examples:
from twilio.twiml.fax_response import FaxResponse
# Receive incoming fax
response = FaxResponse()
response.receive(
action="/fax-received",
method="POST",
media_type="application/pdf",
store_media=True
)
print(response)
# Output: <Response><Receive action="/fax-received" method="POST" mediaType="application/pdf" storeMedia="true"/></Response>
# Reject fax
response = FaxResponse()
response.reject(reason="busy")
print(response)
# Output: <Response><Reject reason="busy"/></Response>TwiML responses are typically generated in webhook handlers that respond to Twilio HTTP requests.
from flask import Flask, request
from twilio.twiml.voice_response import VoiceResponse
app = Flask(__name__)
@app.route("/voice", methods=['GET', 'POST'])
def voice_handler():
"""Handle incoming voice calls"""
response = VoiceResponse()
# Access Twilio parameters
from_number = request.values.get('From')
to_number = request.values.get('To')
call_sid = request.values.get('CallSid')
response.say(f"Hello, you called {to_number} from {from_number}")
return str(response)
@app.route("/sms", methods=['GET', 'POST'])
def sms_handler():
"""Handle incoming SMS messages"""
from twilio.twiml.messaging_response import MessagingResponse
response = MessagingResponse()
# Access message parameters
from_number = request.values.get('From')
body = request.values.get('Body', '').strip()
if body.lower() == 'hello':
response.message("Hi there! How can I help you?")
else:
response.message("Thanks for your message!")
return str(response)Build TwiML responses based on database queries or external APIs.
def create_menu_twiml(menu_options):
"""Generate dynamic menu TwiML"""
response = VoiceResponse()
gather = response.gather(num_digits=1, action="/handle-menu")
gather.say("Please select from the following options:")
for i, option in enumerate(menu_options, 1):
gather.say(f"Press {i} for {option}")
response.say("Invalid selection. Please try again.")
response.redirect("/main-menu")
return response
# Usage
menu_items = ["Sales", "Support", "Billing", "Directory"]
twiml = create_menu_twiml(menu_items)Install with Tessl CLI
npx tessl i tessl/pypi-twilio