Skip to content

Twilio Voice Calls — Making and Receiving Phone Calls Programmatically

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Twilio Voice Calls. We cover key concepts, practical examples, and best practices to help you master this topic.

Twilio Programmable Voice allows you to make and receive phone calls programmatically, with TwiML controlling call flow including text-to-speech, input gathering, call recording, and conferencing.

What You'll Learn

  • How to make outgoing calls with Twilio
  • How to use TwiML for call control
  • How to gather user input during calls

Why It Matters

Phone calls are essential for: automated appointment reminders, verification calls (when SMS fails), interactive voice response (IVR) systems, and outbound sales automation. Twilio Voice handles the telephony infrastructure so you can focus on the call logic.

Real-World Use

DodaTech uses Twilio Voice for: phone-based 2FA (fallback when SMS is delayed), appointment reminder calls with text-to-speech, outbound notifications about account suspensions, and an IVR system for customer support routing.

from twilio.rest import Client
from twilio.twiml.voice_response import VoiceResponse, Say, Gather

client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)

def make_verification_call(to_number, code):
    """Make an automated call that reads a verification code"""
    response = VoiceResponse()
    response.say("Your DodaTech verification code is:", voice='alice')
    response.say(' '.join(code), voice='alice')  # Reads digits individually
    response.say("Repeat: " + ' '.join(code), voice='alice')
    response.hangup()

    call = client.calls.create(
        twiml=str(response),
        to=to_number,
        from_='+15551234567'
    )
    print(f"Call initiated: {call.sid}")
    return call.sid

Interactive Voice Response

@app.route('/twilio/voice/ivr', methods=['POST'])
def ivr_main_menu():
    response = VoiceResponse()
    gather = Gather(
        num_digits=1,
        action='/twilio/voice/handle-menu',
        timeout=5
    )
    gather.say(
        "Welcome to DodaTech support. "
        "Press 1 for account support. "
        "Press 2 for technical support. "
        "Press 3 to speak to a representative.",
        voice='alice'
    )
    response.append(gather)

    # If no input, try again
    response.say("Sorry, I didn't receive any input. Goodbye.")
    response.hangup()

    return Response(str(response), mimetype='text/xml')

@app.route('/twilio/voice/handle-menu', methods=['POST'])
def handle_menu():
    digits = request.form.get('Digits', '')
    response = VoiceResponse()

    if digits == '1':
        response.say("Redirecting to account support.")
        response.dial('+15559876543')  # Forward to agent

    elif digits == '2':
        response.say("Redirecting to technical support.")
        response.dial('+15558765432')  # Forward to tech support

    elif digits == '3':
        response.say("Please hold while we connect you.")
        response.dial('+15557654321')  # Forward to operator

    else:
        response.say("Invalid option.")
        response.redirect('/twilio/voice/ivr')

    return Response(str(response), mimetype='text/xml')

Call Recording

def make_recorded_call(to_number, message):
    """Make a call with recording enabled"""
    response = VoiceResponse()
    response.say(message, voice='alice')
    response.record(
        action='/twilio/voice/recording-complete',
        method='POST',
        max_length=30,
        play_beep=True
    )
    response.hangup()

    call = client.calls.create(
        twiml=str(response),
        to=to_number,
        from_='+15551234567',
        record=True,
        recording_status_callback='/twilio/voice/recording-status'
    )
    return call.sid

@app.route('/twilio/voice/recording-status', methods=['POST'])
def recording_status():
    recording_sid = request.form.get('RecordingSid')
    recording_url = request.form.get('RecordingUrl')
    call_sid = request.form.get('CallSid')
    duration = request.form.get('RecordingDuration')

    database.store_recording(call_sid, recording_sid, recording_url, duration)
    return '', 200

Common Mistakes

1. Not Handling Call Failure Webhooks

Calls can fail for many reasons (busy, no answer, invalid number). Always set a status_callback URL to handle failures.

2. Forgetting to Set a Timeout

Without a timeout, Twilio rings indefinitely (up to the carrier limit). Set timeout=30 seconds for reasonable ringing.

3. Using Incorrect TwiML Verbs

Use Say for text-to-speech, Play for audio files, Gather for input collection, Dial for forwarding. Each serves a different purpose.

4. Not Testing with Multiple Devices

Call behavior differs between landlines, mobile, and VoIP. Test all target device types.

5. Ignoring Call Status Values

Calls transition through queued, ringing, in-progress, completed, busy, failed, no-answer. Handle each status appropriately.

Practice Questions

  1. What TwiML verb reads text aloud during a call?
  2. How do you collect DTMF input from the caller?
  3. How do you record a call?
  4. What status indicates a successful call?
  5. How do you forward a call to an agent?

Answers

  1. <Say>. 2. <Gather> with num_digits and action URL. 3. Set record=True and recording_status_callback. 4. completed. 5. Use <Dial> with the agent's phone number.

Challenge

Build an IVR system with: a main menu with 3 options (account, technical, operator), input collection with timeout and retry, call forwarding to appropriate departments, call recording for quality assurance, and status callbacks for logging.

FAQ

What is Twilio Voice?

An API for making and receiving phone calls with programmatic call control.

What is TwiML?

Twilio Markup Language - XML instructions for controlling call flow.

How do I collect user input during a call?

Use the verb with DTMF digit collection.

Can Twilio read text aloud?

Yes, using the verb with text-to-speech (voices: alice, man, woman).

How do I record calls?

Set record=True on the Call or use the verb in TwiML.

Mini Project

Build a complete phone verification and IVR system: user requests phone verification, Twilio calls the user, reads a verification code using text-to-speech, user presses 1 to confirm, the system marks the phone as verified, and offers a menu for additional options.

What's Next

  • Learn about Twilio Conference for multi-party calls
  • Explore Twilio Conversations API for multi-channel chat
  • Continue to Twilio Functions for Serverless logic

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro