Sending and Receiving SMS with Laravel and Nexmo

Published on by

Sending and Receiving SMS with Laravel and Nexmo image

In this quick tutorial by Phil Leggetter, we’ll cover how you can both send and receive SMS from your Laravel application. We’ll do this using Nexmo, a cloud communications platform that offers APIs for provisioning phone numbers, sending and receiving SMS (which is handy since we’ll use that), making and receiving phone calls and more.


You’ll need a Nexmo account, the Nexmo CLI (Command Line Interface) installed and setup, and your standard prerequisites for a Laravel app. You’ll also need a localtunnel option so that the Nexmo service can make an HTTP request to your local web server. We recommend ngrok.

Getting Started

With that in place let’s create our Laravel SMS application:

composer create-project --prefer-dist laravel/laravel laravel-sms
cd laravel-sms

Next, let’s add the Nexmo Laravel package to composer.json.

"require": {
"nexmo/laravel": "dev-master as 1.0",
"nexmo/client": "dev-master as 1.0"

Note that when these packages come out of beta, you’ll only need to include the nexmo/laravel package and nexmo/client will be brought in as a dependency.

Add the Nexmo Service Provider to your app.php config:

'providers' => [

Note: that you can also add to aliases if you want to use the facade.

Install the packages and copy over the Nexmo configuration file:

› composer update
php artisan vendor:publish

Finally, add your Nexmo API Key and API Secret to /config/nexmo.php, updating the API_KEY and API_SECRET values based on the those found in the API settings in the Nexmo Dashboard.

'api_key' => 'API_KEY',
'api_secret' => 'API_SECRET',

Note: you can obviously set these value from your .env and env(...) if you prefer.

Sending an SMS

Note: for simplicity we’ll add all functionality directly to the app/Http/routes.php file.

Add the following route to app/Http/routes.php:

Route::get('/sms/send/{to}', function(\Nexmo\Client $nexmo, $to){
$message = $nexmo->message()->send([
'to' => $to,
'from' => '@leggetter',
'text' => 'Sending SMS from Laravel. Woohoo!'
Log::info('sent message: ' . $message['message-id']);

You’ll notice that in the above code the from value is set to a string with the value of @leggetter. This will work in the UK, but may not work in other countries. It really depends on the country.

For those of you that need to use a real number here, and for everybody else who’ll need a real number for the next step, let’s look at either using an existing number or buying one.

Listing, Searching and Renting Numbers

One of the prerequisites for the tutorial was the Nexmo CLI. We can use this to do a whole bunch of things including working with phone numbers (Virtual Numbers to be precise) that are associated with our account. If you haven’t already done so you should install and setup the CLI where API_KEY and API_SECRET should be replaced with the API credentials you used earlier:

› npm install -g nexmo-cli
nexmo setup API_KEY API_SECRET

We can now list numbers that we’re already renting, search for numbers that are available to rent, rent those numbers or cancel the rental. Let’s start by seeing if we have any numbers associated with our account:

› nexmo number:list

In the above example, I have a number. If you don’t have a number, you can search for numbers to rent. All you need to know to do that is the two character ISO 3166-1 alpha-2 country code. It’s easier than it sounds. For example, for Great Britain it’s GB and for the United States it’s US. Let’s search for a number to rent in the US:

› nexmo number:search US

If you don’t have a number, you should buy one so that you can send an SMS in countries that require a real outbound number and so that we can also receive SMS later on.

› nexmo number:buy 14155550111 --confirm
Number purchased: 14155550111

Really Sending an SMS

Now if you update your code to use the number you’ve just purchased. Replace the from value with the real number you’ve just purchased or load the number in using env('NEXMO_NUMBER') as we have below:

Route::get('/sms/send/{to}', function(\Nexmo\Client $nexmo, $to){
$message = $nexmo->message()->send([
'to' => $to,
'from' => env('NEXMO_NUMBER'),
'text' => 'Sending SMS from Laravel. Woohoo!'
Log::info('sent message: ' . $message['message-id']);

Then start the server:

› php artisan serve
Laravel development server started on http://localhost:8000/

And navigate to http://localhost:8000/sms/send/YOUR_NUMBER where YOUR_NUMBER should be replaced with your real number including the country code in a e.164 format, the same format that has been shown in all the examples above.

If you check storage/logs/laravel.log you will see a log entry related to the message that has just been sent with a unique message-id at the end of the log entry e.g.

[2016-08-02 13:45:01] local.INFO: sent message: 03000000068F5D97

Receiving an Inbound SMS

For the Laravel application to receive an SMS we need to do a few things:

  1. Ensure our application is reachable by Nexmo using a localtunnel
  2. Create a route to be called when receiving an SMS
  3. Disable CSRF for our SMS receiving route
  4. Inform Nexmo where to make a webhook call to when a message is received

Let’s start by making our application reachable by the Nexmo platform. Assuming you’re using ngrok and your Laravel web server is listening on port 8000 you can do this as follows:

› ngrok http 8000
ngrok by @inconshreveable (Ctrl+C to quit)
Tunnel Status online
Version 2.1.3
Region United States (us)
Web Interface
Forwarding -> localhost:8000
Forwarding -> localhost:8000
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00

As you can see from the above output from ngrok, a subdomain on ngrok has been created, and any requests to that will now be forwarded on to localhost:8000.

With the localtunnel in place we should now create a route to receive the SMS in routes.php:

Route::post('/sms/receive', function(\Nexmo\Client $nexmo){

By default, Laravel won’t allow POST requests to this route without a CSRF token. Since the request to this route will be made by Nexmo, which won’t have a token, we’ll disable CSRF for this route. Add this in App/Http/Middleware/VerifyCsrfToken.php:

protected $except = [

Finally, let’s inform Nexmo where to make the webhook call to when an SMS is received on our number. We can do this using the Nexmo CLI. When executing the following command you should use the phone number you have rented from Nexmo and your ngrok subdomain:

› nexmo link:sms 14155550111
Number updated

When you execute this command, the Nexmo service will attempt to call your /sms/receive route, and you should see those requests in your ngrok terminal.

HTTP Requests
POST /sms/receive 200 OK

If you see anything other than a 200 response, then you’ll need to fix that for the number and webhook association to successfully complete.

The Nexmo PHP Client library provides a way of easily capturing the HTTP parameters that have been sent by Nexmo to the Laravel application and creating an InboundMessage message object that we can work with. Update the /sms/receive code as follows:

Route::post('/sms/receive', function(\Nexmo\Client $nexmo){
$message = \Nexmo\Message\InboundMessage::createFromGlobals();
Log::info('got text: ' . $message->getBody());

Then send an SMS to your rented number and check storage/logs/laravel.log where you will see your message body logged.

[2016-08-02 13:45:01] local.INFO: sent message: 03000000068F5D97
[2016-08-02 14:20:50] local.INFO: sent message: 0300000006917797
[2016-08-02 14:21:17] local.INFO: got text: Sending one back.

Auto-Replying to an Inbound SMS

Finally, let’s create an auto-responder to the inbound message. The Nexmo PHP Client provides a nice way of doing that using the InboundMessage->createReply function:

Route::post('/sms/receive', function(\Nexmo\Client $nexmo){
$message = \Nexmo\Message\InboundMessage::createFromGlobals();
Log::info('got text: ' . $message->getBody());
$reply =$nexmo->message()->send($message->createReply('Laravel Auto-Reply FTW!'));
Log::info('sent reply: ' . $reply['message-id']);

Send a message to your rented number and you’ll get an auto-reply. It’s not quite magic, but it’s pretty close!


In this tutorial, we’ve covered everything you need to know to add sending and receiving SMS, and even auto-replying, to your Laravel application using the Nexmo cloud communications platform.

You can find the code for this sample via

Please don’t hesitate to get in touch with any thoughts or feedback. You can get in touch via email using or contact me on Twitter via @leggetter.

If you do follow this tutorial through and would like some addition credit, please drop us an email with your Nexmo API Key (not secret), tell us you saw this on Laravel News, and we’ll add some more credit to your account.

Many thanks to Nexmo for sponsoring Laravel News this week and for sharing this tutorial on how to get started using their service.

Eric L. Barnes photo

Eric is the creator of Laravel News and has been covering Laravel since 2012.


Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.


Manage your Laravel app as if it was a CMS – edit any text on any page or in any email without touching Blade or language files.

Visit Paragraph
Laravel Forge logo

Laravel Forge

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Forge
Tinkerwell logo


The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

No Compromises logo

No Compromises

Joel and Aaron, the two seasoned devs from the No Compromises podcast, are now available to hire for your Laravel project. ⬧ Flat rate of $7500/mo. ⬧ No lengthy sales process. ⬧ No contracts. ⬧ 100% money back guarantee.

No Compromises
Kirschbaum logo


Providing innovation and stability to ensure your web application succeeds.

Shift logo


Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

LoadForge logo


Easy, affordable load testing and stress tests for websites, APIs and databases.

Paragraph logo


Manage your Laravel app as if it was a CMS – edit any text on any page or in any email without touching Blade or language files.

Lucky Media logo

Lucky Media

Bespoke software solutions built for your business. We ♥ Laravel

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel E-Commerce

E-Commerce for Laravel. An open-source package that brings the power of modern headless e-commerce functionality to Laravel.

Lunar: Laravel E-Commerce
Bacancy - Staff Augmentation logo

Bacancy - Staff Augmentation

Leave your web app development hustles to the leading IT Staff Augmentation Service Providers. Choose from an extensive pool of 1050+ developers and give yourself the sigh of success you deserve with Bacancy. Get In Touch Today!

Bacancy - Staff Augmentation logo

Save hours of manually writing Code Documentation, Comments & DocBlocks, Test suites and Refactoring.
Rector logo


Your partner for seamless Laravel upgrades, cutting costs, and accelerating innovation for successful companies


The latest

View all →
Use Google's Gemini AI in Laravel image

Use Google's Gemini AI in Laravel

Read article
PhpStorm is getting a brand new terminal image

PhpStorm is getting a brand new terminal

Read article
Six Essential Plugins for Visual Studio Code image

Six Essential Plugins for Visual Studio Code

Read article
Modularize Your Laravel Application With the Modular Package image

Modularize Your Laravel Application With the Modular Package

Read article
Handle Money Transactions in Eloquent with Laravel Wallet image

Handle Money Transactions in Eloquent with Laravel Wallet

Read article
Tempo: The Easiest Way to Work With Dates in JavaScript image

Tempo: The Easiest Way to Work With Dates in JavaScript

Read article