Search code examples
pythontwiliocalloutbound

How to retrieve information from outbound Twilio call with Python?


I am new to Twilio and am trying to figure out how to retrieve data from an outbound call I have successfully made using Python 3. I want to be able to retrieve things like what button has been pressed from the recipient.

After reading the Twilio docs for a little bit (then getting a little lost), I think I understand how Twilio works and why I am not able to retrieve data from a phone call. I think the Python program merely establishes a connection from Twilio to a phone number. The recipient can dial any number and I can use the tag to get some info. But how do I direct that info to my Python program? The idea was to have Twilio (somehow) send info back to my Python program and then I can take action (like update a database).

I am guessing that Twilio will throw data somewhere else which then my Python program can go to to retrieve but I do not understand where to learn that skill. I have a basic foundation of Python 3 but not a whole lot on web development. Just some basic HTML5 and CSS3.


Solution

  • Twilio developer evangelist here.

    You may have seen this documentation on gathering user input via keypad in Python on an inbound call.

    When you get an inbound call, Twilio makes the webhook request to find out what to do next and you respond with TwiML, for example, a <Gather> when you want to take information.

    When you make an outbound call, you initiate the call with the REST API and then when the call connects, Twilio makes a webhook request to your URL. It is then that you can respond with TwiML to tell Twilio what to do and you can respond with a <Gather> at this stage too.

    Let's gather input from an outbound call as shown in this documentation.

    First, you purchase a Twilio phone number and configure it with a Ngrok URL: this is a handy tool that opens up your local server to the web via a public URL. When you make an outbound call, you pass it this URL: your-ngrok-url.ngrok.io/voice.

    from twilio.rest import Client
    account_sid = 'your-account-sid'
    auth_token = 'your-auth-token'
    client = Client(account_sid, auth_token)
    
    call = client.calls.create(
        url='https://your-ngrok-url.ngrok.io/voice',
        to='phone-number-to-call',
        from_='your-twilio-number'
    )
    

    The URL in client.calls.create returns TwiML with instructions on what should happen when the user answers the phone call. Let's create a Flask application that contains code to run when the user answers the call.

    from flask import Flask, request
    from twilio.twiml.voice_response import VoiceResponse, Gather
    
    app = Flask(__name__)
    
    @app.route("/voice", methods=['GET', 'POST'])
    def voice():
        # Start a TwiML response
        resp = VoiceResponse()
    

    You would receive user input via keypad with the TwiML Gather verb which is used to collect digits or transcribe speech during a phone call. The Action attribute takes an absolute or relative URL as a value that Twilio makes an HTTP request to once the caller finishes entering digits (or the timeout is reached). That request includes the user's data and Twilio's standard request parameters.

    If you gather digits from the caller, Twilio includes the Digits parameter containing the digits the caller typed in.

        gather = Gather(num_digits=1, action='/gather')
        gather.say('For sales, press 1. For support, press 2.')
        resp.append(gather)
    

    If the recipient doesn't select an option, let's loop them back to the beginning so they can hear the directions again.

        resp.redirect('/voice')
        return str(resp)
    

    However, if they do select an option and type a number into the keypad, Twilio will send a POST request back to the URL hosting your TwiML with the digit they typed. That is how you get user input via button press from the recipient and direct it back to your Python program: with request.values['Digits']. Based on that value (in the choice variable, you can update a database or something accordingly, as shown in the conditionals below.

    @app.route('/gather', methods=['GET', 'POST'])
    def gather():
        """Processes results from the <Gather> prompt in /voice"""
        # Start TwiML response
        resp = VoiceResponse()
    
        # If Twilio's request to our app included already gathered digits,
        # process them
        if 'Digits' in request.values:
            # Get which digit the caller chose
            choice = request.values['Digits']
    
            # <Say> a different message depending on the caller's choice
            if choice == '1':
                resp.say('You selected sales. Good for you!')
                return str(resp)
            elif choice == '2':
                resp.say('You need support. We will help!')
                return str(resp)
            else:
                # If the caller didn't choose 1 or 2, apologize and ask them again
                resp.say("Sorry, I don't understand that choice.")
    
        # If the user didn't choose 1 or 2 (or anything), send them back to /voice
        resp.redirect('/voice')
    
        return str(resp)
    

    Hope this helps!