How to Add Phone Calling Bots to Slack with Python

Make phone calls from Slack using a Python bot

Slack is awesome for text and emoji-based conversations with colleagues. However, sometimes it’s far easier to quickly answer a question over the phone. While Slack is just starting to add voice calling between users, there is no way to patch someone in by their good old telephone number. Let’s add phone calls to Slack by creating a bot with Python, Twilio and the Slack Real Time Messaging API.

Tools We Need

Our bot, which we’ll name callbot, requires a few libraries and APIs. To build our bot we need:

Here’s a handy step-by-step guide to setting up Python, pip and virtualenv.

Our Twilio requirements are:

The Slack dependencies are:

Ensure that Python version 2 or 3 is installed. We’ll configure everything else throughout the remainder of this tutorial.

You can follow along by writing the code in this post or skip ahead to the finished project by cloning the companion GitHub repository.

Configuring Our Environment

Now that we know what tools we need, go to the terminal (or Command Prompt on Windows) and change into a directory where you want to store this project. Within that directory, create a new virtualenv to isolate our application dependencies from other Python projects you’re working on.

Activate the virtualenv:

Depending on how your virtualenv and shell are set up, your prompt should look like something like this screenshot.

virtualenv.png

We’ll use the official slackclient API helper library to access their API to send and receive messages from a Slack channel. Install the slackclient and Twilio helper libraries along with phonenumbers into your virtualenv with the pip command:

We next need to obtain an access token for the Slack Bot and our Twilio API credentials.

Slack Real Time Messaging API

Slack provides programmatic access to their chat application through a web API. Open up the landing page for the Slack Web API and sign up to create a Slack team or sign into your existing account. You can create a new team for free if you don’t have admin privileges on an existing team.
slack-api-sign-in.png

After you have signed in go to the Bot Users page.
custom-bot-users.jpg

Give your bot the name “callbot” and click the “Add bot integration” button.
callbot.png

The page will reload and you’ll see a new generated access token. You can also change the logo to a custom design, like I did with this bot by giving it the Twilio logo.

slack-token.png

Scroll down and click the “Save Integration” button. Your bot is now ready to access the Slack API.

A common practice for Python developers is to export secret tokens like our Slack token as environment variables. Export the token with the name SLACK_BOT_TOKEN:

Awesome. We’re authorized to use the Slack API as a bot. Now we just need a Twilio account and credentials to start handling phone calls.

Twilio Phone Numbers

We need access to the Twilio API to make phone calls from our application. Sign up for a free Twilio account or log into your existing account if you already have one. Our Slack bot will only dial outbound phone calls. Therefore, nothing needs to change on the number configuration screen.

twilio-phone-number.png

With our phone number in hand, go to the Console Dashboard screen and look for your Twilio Account SID and Auth Token:

console-account-sid.png

As we did earlier with the SLACK_BOT_TOKEN, we will use the newly-exported environment variables in our Python script.

On the command line, export Twilio credentials as an environment variables:

There is one more bit of information we need: our bot’s ID in Slack. Next we’ll write a short script to snag that from the Slack API.

Obtaining Our Bot’s ID

Time to write some Python code! We’re going to get warmed up by writing a quick helper Python script to get callbot’s ID because it varies based on the Slack team. We need the callbot ID because it will allow our application code to determine if messages parsed from the Slack Real Time Messaging API are directed at our bot.

This script will also help test that our SLACK_BOT_TOKEN environment variable is set properly. Create a new file named get_bot_id.py with the following code.

The above code imports SlackClient and instantiates it with our SLACK_BOT_TOKEN. When the script is executed by the python command we hit the API for a list of Slack users and get the ID for the one that matches the name callbot.

We only need to run this script once to obtain our bot’s ID.

When we run the script, we’ll get a single line of output with our Bot’s ID.
get-callbot-id.png

Copy the ID and export it as an environment variable named BOT_ID.

Again, the script only needs to be run once to make sure we have the appropriate bot ID for our Slack team. Now we’re ready to code up our Python application that’ll run our callbot.

Coding Our CallBot

We have all the appropriate environment variables set for our Python code to appropriately use the Twilio and Slack APIs. Create a new file named callbot.py and add the following imports.

The os and SlackClient imports should look familiar because we used them earlier in the get_bot_id.py script.

With our dependencies imported we can use them to grab those environment variable values and instantiate the Slack and Twilio clients.

Our code instantiates the SlackClient with our SLACK_BOT_TOKEN from an environment variable. TwilioRestClient automatically pulls the TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN from environment variables with those exact names during its declaration. Continue the Python script with the following lines of code that will handle starting the bot.

SlackClient connects to the Slack Real Time Messaging API WebSocket connection then continuously loops and parses messages from the Messaging firehose. If any of those messages are directed at our bot, a function named handle_command will determine what to do with the command.

Above the Python code we just wrote, add two new functions to parse Slack output and handle commands.

The parse_slack_output function takes messages from Slack and determines if they are directed at our Slack CallBot. If a message starts with a direct message to our bot ID, then we know our bot needs to handle a command. handle_command function is currently a stub function that either passes back a generic help message or has a stub within a condition if the command starts with “call”.

With most of our code in place, let’s test our CallBot by using the python callbot.py command.
callbot-running.png
Go into the Slack channel with CallBot and enter “@callbot: call 14045551234 14155550909” (or replace these two numbers with your own test phone numbers). CallBot will answer back but not really dial numbers.

Our CallBot can respond to commands but it doesn’t place calls yet. We can fix that by adding two new functions named call_command and validate_phone_numbers. handle_command can then invoke call_command instead of just serving as a stub. Change your code to match the entire callbot.py application below. Code changes from our previous version are highlighted.

The above two new functions, call_command and validate_phone_numbers, do the bulk of the work for CallBot. validate_phone_numbers uses the phonenumbers Python library to ensure each phone number is parsable and conforms to at least one phone number type from around the world. call_command ensures that at least two phone numbers are specified and calls validate_phone_numbers for some additional checks. If every phone number is valid then call_command invokes the Twilio Voice API to place each outbound phone call.

Time to run our bot now that all of our code in place. On the command line, execute python callbot.py.
callbot-running.png

In Slack, start giving CallBot commands. You can start testing it with invalid phone numbers. If we specify an invalid phone number format for one or more of the numbers, we’ll get back a helpful error message.
not-valid-format.png

Now try with two legitimate phone numbers.
calling-success.png
Wait a second for the incoming call…
success.png
Now we’re on a conference call with one or more people we’ve dialed through Slack. Time to hash out those questions over the phone so we can get back to coding.

Wrapping Up

Woohoo, our new callbot is all done! Actually, there so much more that can be done with the Slack and Twilio APIs. Here are several more ideas to try out now that you’ve got the basics down:

  1. Implement a persistent backend like PostgreSQL and use it to store a phone number for each username
  2. Add SMS capability to the bot
  3. Use Twilio Lookup to determine if a number is truly valid instead of just parseable
  4. Boost the parser with better parsing and natural language processing so it’s more natural for Slack users to interact with

Questions? Drop a comment below or contact me on these channels:

Twitter: @mattmakai
GitHub: mattmakai
Email: makai@twilio.com
Twitch (Python & Swift live coding):  Team Twilio