Receive an incoming SMS message with PHP and Laravel

Now that you know how to send a message to yourself, learn how to handle incoming SMS messages.

Note:

Before you can get started, you need the following already set up:

  • Set all SMS API configuration settings.
  • PHP 7.3.0 or later and a familiarity with how to create a new file.
  • cURL 7.61.0 or later installed.
  • The lastest version of Laravel (and Composer).
  • ngrok and a familiarity with how to open a local tunnel.

Set up your Laravel application

First, we'll perform a series of setup steps. If you already have Laravel and PHP setup, skip ahead to open an ngrok tunnel to your server.

  1. Create and then navigate to a new folder where you want to store your project.
  1. Open a terminal or command prompt and execute the following command to install Laravel:
    Copy
    Copied
    composer global require laravel/installer

This will install Laravel globally and give you access to the Laravel commands.

  1. Run the following command to create a new Laravel application:
    Copy
    Copied
    laravel new YOUR_app_name

This sets up your web server, installs, and configures all of the necessary dependencies.

  1. Once your web server is created, change directories into the root application folder:
    Copy
    Copied
    cd YOUR_app_name
Note:

Make sure that the fileinfo extension and libcurl are included/enabled in your PHP installation package. More recent versions automatically include these.

Start your server

To fire up the application, start the server with the following command:

Copy
Copied
php artisan serve

If all goes according to plan, a URL with the port appears: Starting Laravel development server: http://127.0.0.1:8000.

Open a tunnel to your server

Since we are testing on our local machine, we need to open a tunnel using ngrok.

  1. In the same root file location, open a separate command prompt or terminal.
  1. Run the following command:
    Copy
    Copied
    ngrok http 8000

    An ngrok session should start.

  1. Copy the forwarding URL connecting to your localhost port. It looks similar to this: https://1234-4567-8-90-12.ngrok.io

In the next step, we'll paste the ngrok URL into Customer Dashboard callback function and tack on our endpoint.

Set up your callback in the Sinch Customer Dashboard

The callback function, or webhook, is what allows incoming messages to be routed back to you. The SMS API will handle webhooks on the backend. So, all you need to do is setup the URL in the Customer Dashboard for each respective service plan ID that you'll be using.

Note:

We are using ngrok for the purposes of testing on our local machine, but you can congifure any callback URL in the Customer Dashboard.

  1. In the Sinch Customer Dashboard, navigate to SMS, then APIs.
  1. Select your service plan ID, then scroll to Callback URL, and click EDIT to add your callback URL.
  1. Paste in the callback URL that ngrok provided and add /api/incomingSMS to the end of the ngrok URL.
    Note:

    This specifies that we want to utlize the API route (/api) in our Laravel app and which endpoint to call. Since we are using the SMS webhook, it is /incomingSMS.

  2. While we're in the Customer Dashboard, navigate to Numbers, then Your virtual numbers. Make a note of your Sinch virtual number as you'll use it to test for an incoming message.

Callback handling complete. Check.

Modify your send file

Now that all the setup steps are complete, we will modify the code that enables receiving SMS messages. This code sets up the route for your web server and contains the logic to respond to incoming callbacks from the Sinch servers through your local tunnel.

  1. Open the api.php file in your project folder (located in \routes).
  1. Populate that file with the api.php code found on this page.
    Note:

    We will not need any of the pre-existing code that is on the api.php file.

api.php

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HandleIncomingSms;
use Illuminate\Support\Facades\Log;

Route::Post('/incomingSMS', function (Request $request) {
    Log::info('Sinch Incoming Request => ', ['sinchRequest' => $request->all()]);
    sendMessage($request);
    return response()->json(200);
});

function sendMessage(Request $request) {
    $service_plan_id = "YOUR_service_plan_id";
    $api_token = "YOUR_API_token";
    $body_text = $request->input('body');

    $payload = [
        'to' => [$request->input('from')],
        'from' => $request->input('to'),
        'body' => "Would ya look at that? You did it! You sent: '{$body_text}'."
    ];

    $curl = curl_init();
    Log::info($payload);
    curl_setopt_array($curl, [
        CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
        CURLOPT_HTTPAUTH => CURLAUTH_BEARER,
        CURLOPT_XOAUTH2_BEARER => $api_token,
        CURLOPT_POSTFIELDS => json_encode($payload),
        CURLOPT_URL => "https://us.sms.api.sinch.com/xms/v1/{$service_plan_id}/batches",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => "POST",
    ]);

    $response = curl_exec($curl);
    $error = curl_error($curl);

    curl_close($curl);

    if ($error) {
        Log::info("cURL Error #:" . $error);
    } else {
        Log::info($response);
    }
}
?>

Fill in your parameters

  1. Modify the code sample with your own parameters as outlined below.
ParameterYour Value
YOUR_service_plan_idThe service plan ID found on your Sinch Customer Dashboard.
YOUR_API_tokenYour API token found in the Customer Dashboard with your corresponding Service Plan ID.
  1. Save the file.
  1. Using a mobile phone, send an SMS message to your Sinch virtual number.

Response

You should receive an SMS back on your own device that says, "Would ya look at that? You did it! You sent: <YOUR_body_text_appears_here>."

The ngrok tunnel will also display a 200 OK status:

Copy
Copied
HTTP Requests
-------------

POST /api/incomingSMS          200 OK

And that's that! You've received an incoming SMS message using PHP through Laravel.

Didn't work?

No worries! It happens. Check the following:

Additional resources

Click here to try more from the /batches endpoint.

Was this page helpful?

api.php

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HandleIncomingSms;
use Illuminate\Support\Facades\Log;

Route::Post('/incomingSMS', function (Request $request) {
    Log::info('Sinch Incoming Request => ', ['sinchRequest' => $request->all()]);
    sendMessage($request);
    return response()->json(200);
});

function sendMessage(Request $request) {
    $service_plan_id = "YOUR_service_plan_id";
    $api_token = "YOUR_API_token";
    $body_text = $request->input('body');

    $payload = [
        'to' => [$request->input('from')],
        'from' => $request->input('to'),
        'body' => "Would ya look at that? You did it! You sent: '{$body_text}'."
    ];

    $curl = curl_init();
    Log::info($payload);
    curl_setopt_array($curl, [
        CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
        CURLOPT_HTTPAUTH => CURLAUTH_BEARER,
        CURLOPT_XOAUTH2_BEARER => $api_token,
        CURLOPT_POSTFIELDS => json_encode($payload),
        CURLOPT_URL => "https://us.sms.api.sinch.com/xms/v1/{$service_plan_id}/batches",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => "POST",
    ]);

    $response = curl_exec($curl);
    $error = curl_error($curl);

    curl_close($curl);

    if ($error) {
        Log::info("cURL Error #:" . $error);
    } else {
        Log::info($response);
    }
}
?>