How to Make and Receive Phone Calls with Python, Bottle and Twilio Voice

November 04, 2016
Written by
Matt Makai
Twilion

Python, Bottle and Twilio Voice

Python web applications that combine the Bottle web framework with the Twilio Voice API can easily make and receive phone calls. Our calls will read a snippet of text then play an MP3 file. The call instructions can be modified to provide other useful actions such as gathering input from the number pad or putting all callers together in a conference call.

Our Project Tools

Our Bottle application will need either Python 2 or 3 to be installed. Python 3 is recommended for new applications. We will also need the following tools throughout this walkthrough:

You can snag all the code for this tutorial in the python-twilio-example-apps GitHub repository. Copy and modify the code however you want – it is all open sourced under the MIT license.

Install Dependencies

Before we write our Python code we will create a new virtual environment to isolate our application dependencies. Open your terminal and execute the virtualenv command to create a new virtualenv:

virtualenv bottlephone

Execute the activate script within the virtualenv, which activates this Python installation for the shell we are working in. Be aware that you need to explicitly activate the virtualenv in each terminal window where you want to execute the Bottle application.

source bottlephone/bin/activate

The command prompt will change when the virtualenv is activated. You should see (bottlephone) $. The following screenshot is what my environment looks like after I ran the activate script:

bottlephone-virtualenv.png

Next use the pip command to install the Bottle and Twilio Python packages into your virtualenv.

pip install bottle twilio

Our two required dependencies will be locally installed once the installation script finishes. Time to write some Python code!

Python Coding with Bottle

The Bottle web application will have three endpoints:

  • / – returns a simple message to let us know our Bottle app is running
  • /twiml – responds with TwiML (a set of instructions written in XML) that instructs Twilio what to do with phone calls
  • /dial-phone/, where “outbound_phone_number” is a phone number in the format ” 12025551234″

With that overview out of the way, we can proceed to writing the code for our initial Bottle application. Create a new file named app.py with the following lines of code:

import os
import bottle
from bottle import route, run, post, Response


app = bottle.default_app()


@route('/')
def index():
    """Returns standard text response to show app is working."""
    return Response("Bottle app up and running!")


if __name__ == '__main__':
    run(host='127.0.0.1', port=5000, debug=False, reloader=True)

Save the file. Make sure your virtualenv is still activated so our code can rely on the Bottle code library. Run the app via the Bottle development server with the following command:

python app.py

Our development server should boot up successfully:

(bottlephone) matt@ubuntu:~/bottlephone$ python app.py
Bottle v0.12.9 server starting up (using WSGIRefServer())...
Listening on http://127.0.0.1:5000/
Hit Ctrl-C to quit.

Test out the app by going to localhost:5000 in a web browser. We should get a simple success message that the app is running and responding to requests.

bottle-dev-server.png

Next we need to obtain a phone number that our Bottle app can use to call other phone numbers.

Getting Our Twilio Number

Our basic Bottle web app runs but what we really want to do is make some phone calls.
In your web browser go to the Twilio website and sign up for a free account. You can also sign into your existing Twilio account if you already have one.

console-phone-numbers.png

The Twilio trial account allows you to dial and receive phone calls to your own validated phone number. To dial and receive calls from any phone number then you need to upgrade your account. Trial accounts are great for initial development before your application goes live but upgraded accounts are where the real power of Twilio is revealed.

Once you are signed into your Twilio account, go to the manage phone numbers screen. On this screen you can buy one or more phone numbers or click on an existing phone number in your account to configure it.

number-config-screen.png

There is nothing for us to configure right now on the phone number configuration page but we will come back to it shortly. Now that we have a phone number in hand, let’s add the final bit of code to our Bottle app to get this app working.

Filling in Our Bottle App

We need to add two new routes to our Bottle app so it can dial outbound phone calls. Modify your existing app.py file with the two new functions below, twiml_response and outbound_call:


import os
import bottle
from bottle import route, run, post, Response
from twilio import twiml
from twilio.rest import TwilioRestClient


app = bottle.default_app()
# copy the account SID and auth token from the Twilio Console and paste below
twilio_client = TwilioRestClient('paste account SID here' , 'auth token here')


# input your Twilio number in the second string on the next line
TWILIO_NUMBER = os.environ.get('TWILIO_NUMBER', '+12023350173')
NGROK_BASE_URL = os.environ.get('NGROK_BASE_URL', '')


@route('/')
def index():
    """Returns standard text response to show app is working."""
    return Response("Bottle app up and running!")


@post('/twiml')
def twiml_response():
    """Provides TwiML instructions in response to a Twilio POST webhook
    event so that Twilio knows how to handle the outbound phone call
    when someone picks up the phone.
    """
    response = twiml.Response()
    response.say("Hello, this call is from a Bottle web application.")
    response.play("https://api.twilio.com/cowbell.mp3", loop=10)
    return Response(str(response))


@route('/dial-phone/')
def outbound_call(outbound_phone_number):
    """Uses the Twilio Python helper library to send a POST request to
    Twilio telling it to dial an outbound phone call from our
    specific Twilio phone number (that phone number must be owned by our
    Twilio account).
    """
    # the url must match the Ngrok Forwarding URL plus the route defined in
    # the previous function that responds with TwiML instructions
    twilio_client.calls.create(to=outbound_phone_number,
                               from_=TWILIO_NUMBER,
                               url=NGROK_BASE_URL + '/twiml')
    return Response('phone call placed to ' + outbound_phone_number + '!')


if __name__ == '__main__':
    run(host='127.0.0.1', port=5000, debug=False, reloader=True)

Make sure to replace the phone number listed above with your Twilio phone number. Also modify the placeholders for the Twilio credentials to properly instantiate the TwilioRestClient.

There is one issue with our local development environment configuration: Twilio won’t be able to reach that /twiml route. We need to deploy our app to a reachable server or use a localhost tunneling tool like Ngrok. Ngrok provides an external URL that connects to a port running on your machine. Download and install the Ngrok application for your operating system.

Run the following command to make our Bottle app on port 5000 available publicly on the Internet.

./ngrok http 5000

Ngrok will start up and provide us with a Forwarding URL, with both HTTP and HTTPS versions.

The Forwarding URL plus the route will instruct Twilio to handle the phone call when someone answers. Insert the Ngrok forwarding URL into the app.py file where NGROK_BASE_URL is specified:

ngrok-forwarding-url.png

One bit to be aware of when using Ngrok is that your Forwarding URL will change whenever you restart the application, so you’ll need to update your code with the latest Forwarding URL.
To get even more out of Ngrok after finishing your Bottle project, make sure to read this 6 awesome reasons to use Ngrok when testing webhooks post.

Making Calls

Make sure your Bottle development server is still running or re-run it with the python app.py command in a shell where your virtualenv is still activated.

Bring up your application in the web browser. Go to “localhost:5000/dial-phone/my-phone-number”, where “my-phone-number” is a number in the ” 12023350173″ E.164 format. For example, here is what happens when I get the call on my iPhone:

success.png

When we pick up the phone call we also see the /twiml route get called via Ngrok.

post-twiml.png

With only a couple of Bottle routes plus Twilio’s Voice API we were able to make phones ring!

Dialing Our Application

Outbound calls are handy, but what about if someone dials our application’s phone number? We have done all the hard work to make inbound calls possible. We just need to copy our Ngrok forwarding URL plus TwiML endpoint into the phone number configuration screen for the phone number we want to dial.

ngrok-number-config.png

Click “Save” and dial your application’s number. You should get the same message and MP3 played as when you dialed the outbound phone call.

Next Steps

We can make and receive phone calls from our Bottle web application using our Twilio phone number. Next you could try to add even more features to your app by going through one of these tutorials:

Questions? Contact me via