https://a.storyblok.com/f/270183/1368x665/3cccd1f4b5/26aug_dev-blog_sms-php_1368x665.jpg

Receiving an SMS with PHP and Vonage

Published on August 11, 2026

Time to read: 4 minutes

I would say the most commonly asked question I get is about sending and receiving SMS texts using a backend or framework. The good news here is that you can accomplish SMS functionality in your app (be it Symfony, Laravel, or Drupal) in relatively few lines of code. Previously, I have written about how to send an SMS in PHP, so in this tutorial, we will learn how to wire up your app to read incoming SMS Webhooks with Slim PHP when the end device replies.

Prerequisites

Create Your Slim Application

Firstly, you will need to create a new Composer project, then fetch Slim.

mkdir recieving-sms && cd recieving-sms

composer init

Follow the interactive CLI instructions, and you can use the defaults for everything except choosing your packages interactively. You should now have a composer.json file: in my case, it looks like this:

Now, we add Slim, Slim’s PSR-7 compatible HTTP handling, and the Vonage PHP SDK:

composer require slim/slim

composer require slim/psr7

composer require vonage/client-core

Adding Our Route

The incoming SMS will be configured to take the form of a POST request with the data in a JSON body. We need to set this up in Slim accordingly, so we need to create the entry point to our app.

touch src/index.php

And then add our code into the new file:

<?php

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Slim\Factory\AppFactory;

require 'vendor/autoload.php';

$app = AppFactory::create();

$handler = function (Request $request, Response $response) {
    return $response->withStatus(204);
};

$app->map(['POST'], '/webhooks/sms', $handler);

$app->run();

We now have an open POST route that responds with HTTP 204. This signals back to Vonage that the webhook has been successfully received. Now we want to hydrate the Webhook into a PHP SDK object and write it to a new log file. We’re going to use Monolog for this:

composer require monolog/monolog

Next, we implement hydrating the Webhook and writing it to our log file in the $handler:

<?php

use Monolog\Level;
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Slim\Factory\AppFactory;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

require 'vendor/autoload.php';

$app = AppFactory::create();

$logger = new Logger('sms');
$logger->pushHandler(new StreamHandler(__DIR__ . '/../log.txt', Level::Info));

$handler = function (Request $request, Response $response) use ($logger) {
   $sms = \Vonage\Messages\Webhook\Factory::createFromArray($request->getBody());
   $logger->info('Message Received' . $sms->toArray());

   return $response->withStatus(204);
};

The app is ready to go; run it using PHP’s built-in web server:

php -S 127.0.0.1:8000 -t src/

Installing the Vonage CLI

Using a JavaScript Package Manager such as npm or yarn, install the Vonage CLI globally:

npm install -g @vonage/cli

Two configurations are now required: set up your API keys with ngrok as part of the setup process, and follow the Vonage setup instructions for the Vonage CLI.

Adding a Vonage Number

We’re going to use the Vonage CLI to make the process slightly easier. Head to the Vonage Dashboard and get your API Key and Secret.

Once you have your API credentials, follow the README in the CLI source code to set it up.

Now use the CLI to view available numbers for purchase:

vonage numbers search us

A list of available numbers will show, so you can then opt to purchase one.

vonage numbers buy <number>

Wiring It All Together

Our last steps are to create an application in the CLI and attach the number to it. Once that’s done, you can send a message to that number, and the webhook will be fired to your app.

Firstly, create the app:

vonage apps create "My App"

Next, give it Messages capability:

vonage apps capabilities update <your-app-id> messages \
--messages-inbound-url=https://example.com/webhooks/inbound \
--messages-status-url=https://example.com/webhooks/status

We’ve added example.com as a placeholder for now, because the CLI will handle our domains as you’ll see later.

We add the number to the application:Using the Vonage Tunnel

vonage apps numbers link <your-app-id> 07730006666

Using the Vonage Tunnel

You will need to expose your Slim application to the outside world so that Vonage is able to send you WebHooks. To do this, you will need to install ngrok. However, instead of using ngrok alone, the Vonage CLI has some useful tooling that wraps around it, making the developer experience a bit more frictionless.

You can use the tunnel feature to open your app up to receive WebHooks with the following command:

vonage tunnel ngrok <your-app-id>

What this command does is pretty useful. Instead of just telling ngrok to serve your application, it runs some update commands on your application instance to change the existing domain for webhooks (in our case, https://example.com) to the ngrok-generated domain it has run in the background (e.g., https://3d3daF.ngrok.com). After the domain, it stitches together the existing relative paths in the application, so in our case, /webhooks/inbound and /webhooks/status. When you quit the tunnel, it also attempts to reset them to their previous value https://example.com in our case).

All the pieces are in place: take your mobile device and send an SMS to your application number. Watch as your app receives a Webhook and populates the log.

Conclusion

It’s pretty apparent that it doesn’t take many lines of code to boot an application that can receive an SMS, just like sending one doesn’t take many lines of code either. When it comes to scaling, however, you’ll want to use more robust monitoring when your application is sending and receiving thousands of requests; you might want to take a look at monitoring application activity with Nightwatch for something like this.

Have a question or want to share what you're building?

Stay connected and keep up with the latest developer news, tips, and events.

Share:

https://a.storyblok.com/f/270183/400x385/12b3020c69/james-seconde.png
James SecondeSenior PHP Developer Advocate

A trained actor with a dissertation on standup comedy, I came into PHP development via the meetup scene. You can find me speaking and writing on tech, or playing/buying odd records from my vinyl collection.