Manage a List of Safe Phone Numbers in PHP with Twilio Verify's Safe List API
Time to read:
Manage a List of Safe Phone Numbers in PHP with Twilio Verify's Safe List API
Twilio's Verify Fraud Guard and Geo Permissions are two excellent ways Twilio helps protect your Verify Service from suspicious activity like SMS Pumping Fraud by automatically blocking risky traffic.
However, sometimes they can also block your own phone numbers, preventing you from sending messages and notifications to your customers. To solve this problem, Twilio introduced the Safe List API, which allows you to maintain a list of phone numbers that will never be blocked by Verify Fraud Guard or Geo permissions.
In short, it lets you mark phone numbers as safe to ensure they are never erroneously blocked.
In this short tutorial, you're going to learn how to integrate a Safe List into your PHP applications so that you can add approved phone numbers to, view existing numbers on, and remove phone numbers when needed.
Let's begin!
Prerequisites
To follow along with the tutorial, you only need the following:
- PHP 8.4
- A Twilio account (either free or paid). Create one if you don't already have one.
- Your preferred PHP editor or IDE, such as NeoVIM or PhpStorm
- Curl, or your network testing tool of choice
- A little bit of command line experience
Create the core project
The first thing to do, as always, is to initialise a new PHP project directory structure and add the required dependencies.
To do that, run the commands below.
Let's quickly go through the dependencies that were just installed:
- laminas-config-aggregator: This package helps initialise the application's DI (Dependency Injection) container
- laminas-servicemanager: This package is the application's DI container
- mezzio-fastroute: This package provides the application's routing layer
- mezzio-problem-details: This package simplifies returning standardised problem responses from requests to the application, saving us time and effort telling the user what went wrong, when something went wrong
- Mini Mezzio: This package simplest setting up Mezzio, the framework that underpins the application.
- PHP Dotenv: This package loads environment variables from dotenv files ( .env) making them available in PHP's $_ENV and $_SERVER superglobals
- Twilio's PHP Helper Library: This package simplifies interacting with Twilio's APIs
Update Composer's configuration
The final thing to do before diving into the code is to update Composer's configuration. To do that, add the following to composer.json:
The configuration above registers a Composer script named "serve" that makes it easier to start the application.
Register the required environment variables
Lastly, in the project's top-level directory, create a file named .env, and in that file paste the configuration below.
Next, log in to your Twilio Console, and from the Dashboard's Account Info panel, copy your Twilio Account SID and Auth Token. Then, paste them into .env as the values for TWILIO_ACCOUNT_SID
and TWILIO_AUTH_TOKEN
respectively.


Write the code
Now, with the core setup out of the way, let's dive in and start building the application. In the public directory, create a PHP file named index.php, then paste the code below into that file.
The code above provides an extremely minimal PHP application, using the Mezzio framework. Stepping through it, the code:
- Loads Composer's Autoloader
- Loads the environment variables in .env
- Initialises the application's DI container and registers a Twilio Rest client as a service in it
- Sets up the applications routing table with a single endpoint ("/ping"), then boots the application.
Start the application and test that it works
While we've not done all that much so far, let's still test that what we've built so far works. After all, it's fun to have a win as early as possible. Start the application by running the following command.
Then, in another terminal tab, run the following command with curl which makes a request against the "/ping" endpoint.
You should see output similar to the following, printed to the terminal.
Add a route for adding phone numbers to the Safe List
Now, let's get in and build the first of the three Safe List endpoints. We'll start with the one that allows us to add a phone number, by adding the following code in public/index.php after the definition of the "/ping" route:
The code defines a route that accepts only POST requests to "/safe-list", with requests handled by an anonymous class that implements RequestHandlerInterface; specifically, the class' handle()
method.
The method checks if the POST data contains an element named phone_number which contains an E.164-formatted phone number. If not, it returns a JSON response containing the message "The phone number to add to the Safe List must be in E.164 format.", along with an HTTP 400 Bad Request response code.
Otherwise, using Twilio's PHP Helper Library the code attempts to add the phone number to the Safe List. If the request fails, a Problem Details message is returned. If you're not familiar with it, it's:
…a way to carry machine-readable details of errors in a HTTP response to avoid the need to define new error response formats for HTTP APIs.
It's a bit over the top, but we're doing this to provide the user with all the applicable information on why the phone number could not be added to the Safe List in a standardised way.
If the number was successfully added, then the number's Safe List SID is returned as a JSON response.
Add in the validation functions
Now, you need to create the utility functions that were called in the previous route: isValidPhoneNumber()
and getErrorResponse()
. To do that, create a folder within src called App and then create a new file named utilities.php in the src/App directory. Then, in the new file, paste the code below.
As I mentioned, the code defines:
- isValidPhoneNumber: uses a small regex (regular expression),
^\+[1-9]\d{1,14}$
, to validate the supplied phone number. - getErrorResponse: creates and returns a Problem Details message, with an HTTP 400 Bad Request status and the supplied message string.
Now, run the following command to complete the process:
Add a route for viewing phone numbers on the Safe List
Next, let's add the ability to check if a phone number is already on the Safe List. Do this by adding the following code in public/index.php, after the route that you just added.
This route accepts GET requests to the "/safe-list" endpoint with the phone number in E.164 format appended. Similar to the previous route, it checks if the phone number is both present and formatted correctly. If not, it returns a Problem Details message containing the message: "The phone number to delete must be in E.164 format.".
Otherwise, it makes a request to the Safe List API to check if the provided number is in the Safe List. If not, it returns an applicable Problem Details response. If it is, it returns the message "Phone number is on the safe list." as a JSON response, along with the phone number's Safe List SID.
Add a route for deleting phone numbers from the Safe List
Finally, let's add the ability to remove a phone number from the Safe List, by adding the following code to public/index.php after the previous route definition.
Test that the application works as expected
Now that the application's complete, it's time to test that it works.
Add a phone number to the Safe List
Start by adding your mobile/cell phone number to the Safe List by replacing <Your Phone Number>
with your phone number — in E.164 format — in the command below, then running it in a new terminal tab.
On success, the Safe List SID of the phone number will be printed to the terminal. If the command fails, however, such as because the phone number is not in E.164 format, you will see the following message printed to the terminal:
Check that the phone number is on the Safe List
Now that the phone number is on the Safe List, it's time to be doubly-sure, by checking. To do that, in the command below replace <Your Phone Number>
with your E.164-formatted phone number, then run it:
You should see the following message printed to the terminal, confirming that your phone number is on the Safe List:
Alternatively, you could try adding your phone number to the Safe List again. You should see terminal output (formatted for readability) similar to the following, confirming that it is already on the list:
Delete the phone number from the Safe List
Finally, let's remove your phone number from the Safe List. To do that, in the command below replace <Your Phone Number>
with your E.164-formatted phone number, then run it:
On success, you will see a message similar to the following, printed to the terminal:
That's how to manage a list of safe phone numbers in PHP with Twilio Verify's Safe List API
Now you know how to maintain a list of phone numbers that will never be blocked by Verify Fraud Guard and Geo permissions, by using Twilio's Safe List, while still avoiding suspicious messages from being sent by your Verify Service.
I hope that you see the value and make use of it in your PHP applications to help ensure that they're as secure as possible.
Happy building!
Matthew Setter is (primarily) the PHP, Go, and Rust editor on the Twilio Voices team. He’s also the author of Mezzio Essentials and Deploy with Docker Compose. You can find him at msetter[at]twilio.com. He's also on LinkedIn and GitHub.
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.