Serverless Twilio Webhooks on AWS with Lambda Function URLs

April 21, 2022
Written by
Reviewed by

Serverless Twilio Webhooks on AWS with Lambda Function URLs

Serverless platforms are ideal for the deployment of webhooks such as those used by Twilio services, as they provide flexibility and scalability without the complications involved in hosting on your own infrastructure.

In this tutorial you are going to learn how to create a Twilio SMS webhook written in Python using AWS Lambda, with its brand new function URLs feature.

Requirements

To work on this tutorial you will need the following items:

Create a Python webhook

To get started, open a terminal window and navigate to the place where you would like to set up your project.

Create a new directory called lambda-webhook where your project will live, and change into that directory using the following commands:

mkdir lambda-webhook
cd lambda-webhook

Following Python best practices, you are now going to create a virtual environment, where you are going to install the Python dependencies needed for this project.

If you are using a Unix or Mac OS system, open a terminal and enter the following commands to create and activate your virtual environment:

python3 -m venv venv
source venv/bin/activate

If you are following the tutorial on Windows, enter the following commands in a command prompt window:

python -m venv venv
venv\Scripts\activate

Now you are ready to install the Python dependencies used by this project:

pip install twilio flask

The two Python packages needed by this project are:

To ensure that the Python environment that will be created in AWS is identical to your local one, save the complete list of the installed dependencies to a requirements.txt file with the following command:

pip freeze > requirements.txt

Then create a file called webhook.py for the SMS webhook and write the following code on it:

import os
from flask import Flask, request, abort
from twilio.request_validator import RequestValidator
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)


@app.route('/', methods=['POST'])
def reset():
    validator = RequestValidator(os.environ.get('TWILIO_AUTH_TOKEN'))
    if not validator.validate(request.url, request.form,
                              request.headers.get('X-Twilio-Signature')):
        abort(400)
    resp = MessagingResponse()
    resp.message('Hello from AWS Lambda!')
    return str(resp), 200, {'Content-Type': 'application/xml'}

This short webhook application uses Flask to create a web server that listens for POST requests. Twilio will make requests to this endpoint when your Twilio phone number receives an SMS.

The function first validates that the incoming request has a valid Twilio signature, which is important to verify the legitimacy of the request. If the signature cannot be validated, the request is discarded.

If the signature is valid, then the webhook generates a TwiML response that replies to the SMS with a greeting.

As you can see in the code above, to validate the Twilio signature, the application needs access to the Twilio Auth Token associated with your account, which it obtains from an environment variable. Go back to your terminal session and configure this variable as follows:

export TWILIO_AUTH_TOKEN=xxxxxxxxx

If you are following this tutorial on Windows, use set instead of export in your command prompt window.

You will need to replace the xxxxxxxxx placeholder in the command above with the correct value that applies to your account. You can find your Twilio Auth Token in the main dashboard of the Twilio Console, under “Account Info”:

Twilio credentials in the Console

The Python webhook is now complete. In the following sections you’ll learn how to deploy it to AWS Lambda.

Install the Serverless framework

The Serverless framework is an open-source deployment and monitoring tool for serverless functions on AWS Lambda. You are going to use it to manage and deploy our webhook application.

You can install the Serverless framework with the following command:

npm install -g serverless

To ensure that you have successfully installed it, make sure you can access the sls command documentation as follows:

sls –help

Create a Serverless configuration file

Deployments with the Serverless framework are managed with a configuration file called serverless.yml. Create this file in the project directory and write the following contents on it:

service: lambda-webhook

provider:
  name: aws
  runtime: python3.9
  environment:
    TWILIO_AUTH_TOKEN: ${env:TWILIO_AUTH_TOKEN}

plugins:
  - serverless-wsgi
  - serverless-python-requirements

functions:
  webhook:
    handler: wsgi_handler.handler
    url: true

custom:
  wsgi:
    app: webhook.app
  pythonRequirements:
    pythonBin: python

The provider section of the configuration file establishes AWS Lambda as the deployment platform, sets the runtime to Python 3.9, and exports the TWILIO_AUTH_TOKEN environment variable so that it is deployed along with the function.

The plugins section makes a reference to two plugins. These are Node.js packages that need to be installed. To do this, run the commands below in the project directory:

npm init -y
npm install serverless-wsgi serverless-python-requirements

These commands will add two files to the project named package.json and package-lock.json, which track the Node.js dependencies you just installed. The actual packages are installed in the node_modules subdirectory.

The functions section of the configuration defines the actual service that will be deployed, which is composed of a single function. The handler key inside the webhook function points to the WSGI adapter provided by the Serverless WSGI plugin. The url key tells Serverless that it should provision the function with a public URL, which will be later configured on the Twilio side.

The custom section provides configuration options for the installed plugins. The WSGI plugin needs to know the location of the WSGI application callable. The Python Requirements plugin is given the location of the Python interpreter to use during the deployment. Passing python here makes the plugin use the interpreter from the activated virtual environment.

Deploy the function to AWS Lambda

Your webhook project is now complete. To be able to deploy the webhook to AWS, you need to have your AWS access key credentials installed as environment variables that the Serverless framework can access.

These variables are AWS_ACCESS_KEY and AWS_ACCESS_KEY_SECRET. If you’ve never requested these credentials from AWS, the Serverless framework documentation has detailed instructions on how to obtain them.

After you have set up your AWS access key environment variables, you can deploy your webhook with this command:

sls deploy

The command takes a few minutes to create a Python Lambda function and deploy it to AWS. Once the deployment completes, you will see the public URL that was assigned to the deployed webhook:

(venv) $ sls deploy
Running "serverless" from node_modules

Deploying lambda-webhook to stage dev (us-east-1)
Python executable not found for "runtime": python3.9
Using default Python executable: python
Packaging Python WSGI handler...

✔ Service deployed to stack lambda-webhook-dev (556s)

endpoint: https://xxxxxxxxxxxxxxxxxxxxxxx.lambda-url.us-east-1.on.aws/
functions:
  webhook: lambda-webhook-dev-webhook (51 MB)

Toggle on monitoring with the Serverless Dashboard: run "serverless"

Configure the Webhook for Twilio SMS

Copy the URL shown in the endpoint line of the deploy command’s output. This is the URL assigned to your webhook.

On the Twilio Console, go to “Phone Numbers”, then “Manage” and then “Active Numbers”. Select your Twilio phone number from the list to open its configuration page.

On the phone number configuration, scroll down to the “Messaging” section and paste the lambda function URL in the “A message comes in” field. Make sure the dropdown on its left is set to “Webhook” and the one on the right to “HTTP POST”.

Twilio webhook configuration

Pick up your phone and send an SMS to your Twilio number. Twilio will deliver the message to the webhook running on AWS Lambda, which will respond to you with a greeting!

SMS demonstration

Conclusion

Production deployment of webhooks to AWS Lambda with the Serverless framework is a convenient option that has just become even more powerful with Lambda’s new function URLs. I hope you’ve found this tutorial useful and apply the techniques that you learned to your own webhooks.

I’d love to see what you build!

Miguel Grinberg is a Principal Software Engineer for Technical Content at Twilio. Reach out to him at mgrinberg [at] twilio [dot] com if you have a cool project you’d like to share on this blog!