How to Handle Twilio Webhooks With Go and DigitalOcean Functions
Time to read: 6 minutes
How to Handle Twilio Webhooks With Go and DigitalOcean Functions
In this tutorial, we’ll explore how to receive and process Twilio webhooks using Go and DigitalOcean Functions.
Twilio webhooks provide a convenient way to receive real-time notifications about various events of your Twilio account. By leveraging DigitalOcean Functions, a serverless computing platform, you can handle these webhooks efficiently and perform custom actions based on the webhook data.
Technical requirements
To follow along, you’ll need the following:
- A free Twilio account. If you are new to Twilio, click here to create a free account
- Go 1.19 or above
- A DigitalOcean account, and doctl, which is DigitalOcean’s command line interface tool.
Create a DigitalOcean Function
To start creating a DigitalOcean (DO) Function, you will use the doctl command line tool.
However, you need a personal access token to be able to use doctl. To generate one, head over to the API section of DigitalOcean's Dashboard. Click the Generate New Token button and fill in the form details, following the screenshot below. The account and function scopes are the custom scopes your token will need for this tutorial.
Before you can do anything with doctl, you need to initialize it to use your account. Do this by running the following command:
Make sure to provide the access token you generated when you’re prompted to provide one.
You also need to install support for serverless functions. You can do that by running the following command:
This will install and download the serverless extension. Once that is completed, you are now ready to initialize a new function project using a helper command that doctl tool provides.
To work with DigitalOcean Functions via the command line using doctl, you need to connect doctl to a Functions namespace. Namespaces are used to isolate and organize functions and their settings. If this is your first time working with DO Functions, you’ll need to create a namespace before you can connect to it and start deploying Functions. Do this by running the following command:
The --label
flag is used to specify the name of the namespace, while the --region
flag indicates which region the namespace should be in. Feel free to update the region to one close to where you live.
Next, from the directory where you want your project to reside, run the following to create a new function project.
This will create a project directory named twilio that contains a project.yml configuration file, a packages directory containing the sample package, a function directory named hello, and the sample “Hello world” function code (in hello.go).
Here’s an outline of what the current directory structure will look like:
This is good for a start. However, you’ll need to rename some of the directories and files to align with the purpose of the function.
- Rename the sample package directory to twilio
- Rename the hello function directory to webhooks
- Rename the hello.go file to main.go
Here’s an outline of what the new directory structure is supposed to, now, look like:
With the file and directory structure updated, open the project directory in your text editor or IDE of choice. Then, replace the contents of the project.yml file in the root of the project’s directory with the following:
The packages' and actions' names are now consistent with the naming used for the directories. You’ve also added the following environment variables: TWILIO_AUTH_TOKEN
and TWILIO_WEBHOOK_URL
, which the function needs to run. The environment variables will be fetched from a .env file you’ll create shortly using Templating.
Install the dependencies
Next, we’ll install the only dependency the project will need, Twilio's Go helper library used to simplify communicating with Twilio’s API. In this case, we’ll be using the library to validate incoming Twilio webhook requests and construct TwiML responses.
First, navigate to the webhooks directory within the project and run the following code to initialize a Go module.
Next, to install the dependencies, run the following commands:
This will install the dependency and create the entries needed in go.mod and go.sum. During deployment, the build process uses these files to download your third-party modules and build your function.
Build the Function
Replace the contents of the packages/twilio/webhooks/main.go file with the following code:
We’ve defined a Main()
function that serves as the entry point for our code and DigitalOcean Function. It processes incoming Twilio webhooks, validates the request signature, and responds with a TwiML message.
The Main()
function is passed two parameters. The first parameter is a Go Context (context.Context
) that represents the function’s execution context. The second parameter is a map that contains information about the HTTP request.
The incoming request from a Twilio webhook is of type application/x-www-form-url-encoded
, so we created a map and populated it with all of the key/value pairs from the request. Currently, some additional legacy keys such as __ow_headers
, __ow_method
and __ow_path
may be available in the event parameter. However, we don’t need the values of these keys, so they’re skipped.
To verify the request is authentic, you can use the RequestValidator
struct from Twilio's Go helper library. The struct is initialized by passing in your Twilio Auth Token. The Validate()
method on the struct is called passing in the webhook URL, which is obtained as an environment variable using os.Getenv()
, the map with the request body, and the signature contained in the X-Twilio-Signature
header. If this method returns false
, the request is aborted with a status code of 400.
Deploy the Function
Before you can deploy the Function to DigitalOcean, you need to configure your environment variables. Head over to your Twilio Console, and take note of your Auth Token.
Head back to the root of the project’s directory and create a .env file. Then, update the file with the following:
Then, replace the TWILIO_AUTH_TOKEN
with the actual value you copied from your Twilio Console. For the TWILIO_WEBHOOK_URL
field, you can use a random string as the value there, temporarily. You’ll be updating that field shortly after the Function has been deployed.
Next, move to the project directory's parent directory and run the command below to deploy the function:
Once the function has been successfully deployed, you can fetch the URL where the function was deployed by running the command below:
The command will output a URL similar to the one below:
Head back to the project’s directory, and update the TWILIO_WEBHOOK_URL
field in the .env file with the URL printed to your terminal.
Next, change out of the project and then redeploy the project by running the deploy command, as follows:
Once you have deployed the function, you can get the function URL by running the following command:
You can now take the function URL and configure your Twilio account with it.
Configure your Twilio account
Open your Twilio Console and head to Phone Numbers > Manage > Active Numbers. There, select your Twilio phone number.
You’ll be presented with a screen that shows you details about the phone number. Under the Messaging Configuration section:
Set Configure with to "Webhook, TwiML Bin, Function, Studio Flow, Proxy Service"
Set "A message comes" in to "Webhook"
Paste the function URL in the "A message comes in" field
Ensure the request method is set to "HTTP POST"
Click the Save configuration button at the bottom of the page to save the settings
This is the endpoint Twilio will send a request to whenever your Twilio phone number receives a message.
Test that the application works
You can now send an SMS message to your Twilio phone number, and the DigitalOcean function should have been triggered.
You should receive a reply SMS with the body "Received webhook signature". And, if you look in the Overview section of your Function, in the DigitalOcean dashboard, you should see Activation Count set to 1 as in the screenshot above.
That's how to receive Twilio Webhooks using Go and DigitalOcean Functions
In this tutorial, you’ve learned how to create a DigitalOcean Function using Go to handle Twilio webhooks. We covered setting up the project, validating Twilio Webhook requests, and deploying the Function to DigitalOcean.
This serverless approach provides a scalable and efficient way to process events from Twilio without managing server infrastructure. This tutorial can serve as the foundation for building more complex serverless functions with DigitalOcean and Twilio.
Dotun is a backend software engineer who enjoys building awesome tools and products. He also enjoys technical writing in his spare time. Some of his favorite programming languages and frameworks include Go, PHP, Laravel, NestJS, and Node. You can find him at https://dotunj.dev/, https://github.com/Dotunj, and https://twitter.com/Dotunj_
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.