How to Configure Twilio get all SMS in Laravel

 



To retrieve all SMS messages using Twilio in a Laravel application, you can use the Twilio PHP SDK. Follow these steps to configure Twilio and get all SMS messages in a Laravel project:

  1. Install Twilio PHP SDK:

    • Open a terminal and navigate to your Laravel project's root directory.

    • Install the Twilio PHP SDK using Composer:

      bash
      composer require twilio/sdk
  2. Get Twilio API Credentials:

    • Obtain your Twilio Account SID and Auth Token from the Twilio Console.
  3. Configure Twilio in Laravel:

    • Open your Laravel project's .env file and add the following lines, replacing the placeholders with your Twilio credentials:

      dotenv
      TWILIO_SID=your_twilio_sid TWILIO_AUTH_TOKEN=your_twilio_auth_token TWILIO_PHONE_NUMBER=your_twilio_phone_number
    • Create a configuration file for Twilio (config/services.php):

      php
      return [ 'twilio' => [ 'sid' => env('TWILIO_SID'), 'token' => env('TWILIO_AUTH_TOKEN'), 'from' => env('TWILIO_PHONE_NUMBER'), ], ];
  4. Write Laravel Code to Retrieve SMS Messages:

    • Create a controller or add the following code to an existing controller or route:

      php
      <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Twilio\Rest\Client; class TwilioController extends Controller { public function getAllSMS() { $twilioSid = config('services.twilio.sid'); $twilioToken = config('services.twilio.token'); $twilioPhoneNumber = config('services.twilio.from'); $client = new Client($twilioSid, $twilioToken); // Retrieve all SMS messages $messages = $client->messages->read(['from' => $twilioPhoneNumber]); foreach ($messages as $message) { // Output or process each message echo 'SID: ' . $message->sid . ', Body: ' . $message->body . PHP_EOL; } } }
  5. Route Setup:

    • Add a route in your web.php file or routes/web.php:

      php
      use App\Http\Controllers\TwilioController; Route::get('/get-all-sms', [TwilioController::class, 'getAllSMS']);
  6. Run Your Laravel Application:

    • Run your Laravel application using the following command:

      bash
      php artisan serve
    • Access the route in your browser or via an HTTP client like Postman:

      bash
      http://localhost:8000/get-all-sms

This example assumes you've set up your Laravel environment with the necessary credentials. Adjust the code according to your specific requirements.


----------------------------------------------------------------------------------------------------

 Introduction

Twilio integrations have been a lot more common than I thought during the last few years. So I wanted to write the article I wish I have found the first time a had to do it.

Twilio’s SMS API is a flexible building block that can take you from sending your first text message all the way to sending and receiving millions.

In this article, I will talk about how to set up a Laravel application Twilio configuration and start sending SMS.

After that, we will dig deeper into how to keep track of the status of sent messages and keep a local updated representation of Twilio messages.

Finally, we will prepare the application to receive notifications every time your defined Twilio phone number gets a message and then store the received message locally.

Configuration and sending the first SMS

1. Get Twilio Credentials and Phone Number

Go to your Twilio dashboard at https://console.twilio.com/ and find your account SID, Auth Token, and Phone Number. If you don’t have a phone number yet you can create a trial phone number.

Keep in mind that a trial phone number can only send SMS to verified phones. This means you will have to add the phone number you intend to send messages to a verified numbers list.

2. Add Twilio Credentials to Laravel configuration.

.env fileTWILIO_SID=YOUR_ACCOUNT_SID
TWILIO_AUTH_TOKEN=YOUR_ACCOUNT_AUTH_TOKEN
TWILIO_FROM_NUMBER=YOUR_ACCOUNT_FROM_NUMBER(e.g. +1XXXXXXXXXX)
--------------------------------------------------------------/config/app.php'twilio' => [
'sid' => env('TWILIO_SID'),
'auth_token' => env('TWILIO_AUTH_TOKEN'),
'from_number' => env('TWILIO_FROM_NUMBER')
]

3. Install Twilio SDK for PHP

composer require twilio/sdk

4. Create Twilio Service Class

It is convenient to handle all Twilio SMS operations from a single class that is globally available. So every time you send a message you will do it through this service.



<?php
namespace App\Services\Communications;
use Exception;
use Twilio\Rest\Client;
class TwilioService
{
/**
* Twilio Client
*/
protected $client;
/**
* Twilio instance parameters
*/
protected $sid;
protected $token;
protected $from_number;
/**
* Status Callback Url
*/
protected $status_callback_url;
/**
*
* @throws \Twilio\Exceptions\ConfigurationException
*/
public function __construct()
{
$this->sid = config('app.twilio.sid');
$this->token = config('app.twilio.auth_token');
$this->from_number = config('app.twilio.from_number');
$this->client = new Client($this->sid,$this->token);
}
public function sendMessage($to, $body) : array
{
$result = ['success' => false, 'data' => [], 'message' => ''];
try{
$options = array();
$options['body'] = $body;
$options['from'] = $this->from_number;
$apiResponse = $this->client->messages->create($to, $options);
$result['data'] = $apiResponse->toArray();
if(!empty($result['data']['errorCode'])) {
throw new Exception('Send SMS request failed');
}
$result['success'] = true;
$result['message'] = 'SMS request success';
}catch(Exception $ex){
$result['success'] = false;
$result['message'] = $ex->getMessage();
}
return $result;
}
/**
* Get Twilio Client
* @return Client
*/
public function getClient()
{
return $this->client;
}
}

Remember to bind the service so it is globally accessible. In this case, we will create a provider CustomServiceProvider and bind TwilioService in the boot function.

php artisan make:provider CustomServiceProvider

<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class CustomServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
$this->app->bind('TwilioService', \App\Services\Communications\TwilioService::class);
}
}


And then add App\Providers\CustomServiceProvider::class into the $providers array on config/app.php.

Now the TwilioService should be available and we can test it from anywhere.

Also not required, but it will be convenient to add a new channel at /config/logging.php to log Twilio operations, at least for debugging.

...'twilio' => ['driver' => 'single','path' => storage_path('logs/twilio.log'),'level' => 'debug',],...

5. Create Twilio SMS Controller.

If you only care about sending messages then you don’t really need to create a controller. You can test and use the TwilioService sendMessage function from anywhere.

For this implementation, we will use this controller to provide a sendTest function. Later it will also be used to handle Twilio SMS Status Callback requests and Twilio SMS Received requests.

php artisan make:controller TwilioSmsController

<?php
namespace App\Http\Controllers;
use Exception;
use Illuminate\Http\Request;
class TwilioSmsController extends Controller
{
/**
* Test sms send
* @return mixed
*/
public function sendTest(Request $request) {
try {
// Make sure it is E.164 formatting
$toPhoneNumber = 'TO_PHONE_NUMBER_YOU_ARE_TESTING';
$sendResult = app('TwilioService')->sendMessage($toPhoneNumber, 'Hi, this is a test');
if(!isset($sendResult['success']) || !$sendResult['success']) {
throw new Exception(($sendResult['message'] ?? ''));
}
return $sendResult;
}catch (Exception $ex) {
return 'Send SMS Failed - '.$ex->getMessage();
}
}
}


Add testing endpoint to your API routes.

Route::any('/twilio/send-test',[TwilioSmsController::class, 'sendTest'])->name('twilio.send-test');

You are ready to make your first test. Hopefully, everything goes right on the first try. If not, you will get a debug error message.

Common errors you can get:

That’s it! 🎉 If you only need to send messages then you are ready to go.

If you want to keep track of the messages you sent and also be able to receive messages in your application then keep reading 👀.

Track Twilio SMS status changes

When we make a send SMS request to Twilio the message has to go through a sequence of statuses.

  • accepted
  • queued
  • sending
  • sent
  • delivery_unknown
  • delivered
  • undelivered
  • failed

The response we get from making a successful send SMS request will tell us that the message status is queued. This just means that Twilio accepted the request and it was added to the queue of messages to send, but we don’t know if it was actually sent.

If we want to keep track of an SMS status we have to provide a statusCallback parameter on each request. The statusCallback will be the URL to a webhook in our application that will be prepared to receive requests from Twilio.

1. Create TwilioSms Model and TwilioSmsLog Model.

TwilioSms will represent a Twilio SMS in our application and TwilioSmsLog will represent each event related to an SMS (status change, error, etc).

php artisan make:model TwilioSms -m
php artisan make:model TwilioSmsLog -m

Models:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TwilioSms extends Model
{
use HasFactory;
protected $table = 'twilio_sms';
protected $guarded = [];
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TwilioSmsLog extends Model
{
use HasFactory;
protected $table = 'twilio_sms_log';
protected $guarded = [];
}


Migrations:


<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTwilioSmsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('twilio_sms', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('sid', 500);
$table->enum('direction', ['sent','received']);
$table->string('from', 50);
$table->string('to', 50);
$table->string('body', 1600)->nullable()->default(null);
$table->enum('status', ['request_error','accepted','queued','sending','sent','receiving','received','delivered','undelivered','failed','read'])->default('request_error');
// Indexes
$table->unique(['sid']);
$table->index(['from']);
$table->index(['to']);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('twilio_sms');
}
}

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTwilioSmsLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('twilio_sms_log', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('twilio_sms_id')->unsigned()->nullable()->default(null);
$table->string('sms_sid', 500)->nullable()->default(null);
$table->string('sms_message_sid', 500)->nullable()->default(null);
$table->enum('event', ['send_sms_request',
'send_sms_request_error',
'message_received',
'segment_status_changed',
'status_changed',
'invalid_request_sid_not_defined',
'twilio_sms_not_found',
'generic_error',
'not_categorized'])->default('not_categorized');
$table->string('new_status', 191)->nullable()->default(null);
$table->json('details')->nullable()->default(null);
$table->timestamps();
// Indexes
$table->index(['twilio_sms_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('twilio_sms_log');
}
}


2. Create status callback webhook route and implement Twilio Request Validation middleware.

Add new endpoint to api routes.

/**
* Twilio statusCallBack webhook
* is-twilio-request middleware makes sure only twilio has access to this route
*/
Route::any('/twilio/webhook/status-changed', [TwilioController::class, 'statusChanged'])->middleware(['is-twilio-request'])->name('api.twilio.status-changed');

Notice that we are using the middleware is-twilio-request. This route will be open to the public so we need to make sure that it only serves valid requests from Twilio. We can accomplish that by using the RequestValidator method provided by the Twilio PHP SDK.

Create Middleware

php artisan make:middleware TwilioRequestIsValid

<?php
namespace App\Http\Middleware;
use Closure;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Twilio\Security\RequestValidator;
class TwilioRequestIsValid
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
try {
$twilioToken = config('app.twilio.auth_token');
if(empty($twilioToken)) {
throw new Exception('Token not found');
}
$requestValidator = new RequestValidator($twilioToken);
$requestData = $request->toArray();
// Switch to the body content if this is a JSON request.
if (array_key_exists('bodySHA256', $requestData)) {
$requestData = $request->getContent();
}
$isValid = $requestValidator->validate(
$request->header('X-Twilio-Signature'),
$request->fullUrl(),
$requestData
);
if (!$isValid) {
throw new Exception();
}
}catch (\Throwable $ex) {
return new Response(['success' => false, 'message' => 'Failed Authentication'], 403);
}
return $next($request);
}
}




Add the new middleware to app/Http/Kernel.php $routeMiddleware array.

/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
*
@var array
*/
protected $routeMiddleware = [
...
'is-twilio-request' => \App\Http\Middleware\TwilioRequestIsValid::class,
];

3. Update Twilio Service. Add status callback, create TwilioSmsModel on send and log.

The Twilio Service final version will be:


<?php
namespace App\Services\Communications;
use Exception;
use Illuminate\Support\Facades\Log;
use Twilio\Rest\Client;
use App\Models\TwilioSms;
use App\Models\TwilioSmsLog;
class TwilioService
{
/**
* Twilio Client
*/
protected $client;
/**
* Twilio instance parameters
*/
protected $sid;
protected $token;
protected $from_number;
/**
* Status Callback Url
*/
protected $status_callback_url;
/**
*
* @throws \Twilio\Exceptions\ConfigurationException
*/
public function __construct()
{
$this->sid = config('app.twilio.sid');
$this->token = config('app.twilio.auth_token');
$this->from_number = config('app.twilio.from_number');
$this->status_callback_url = route('api.twilio.status-changed');
$this->client = new Client($this->sid,$this->token);
}
public function sendMessage($to, $body) :array {
$result = ['success' => false, 'data' => [], 'message' => '', 'twilio_sms_id' => null];
try{
$options = array();
$options['body'] = $body;
$options['from'] = $this->from_number;
$options['statusCallback'] = $this->status_callback_url;
$apiResponse = $this->client->messages->create($to, $options);
$result['data'] = $apiResponse->toArray();
if(!empty($result['data']['errorCode'])) {
throw new Exception('Send sms request failed');
}
$result['success'] = true;
$createdSms = TwilioSms::create([
'sid' => $result['data']['sid'],
'direction' => 'sent',
'from' => $result['data']['from'],
'to' => $result['data']['to'],
'status' => $result['data']['status'],
'body' => $result['data']['body'],
]);
$result['twilio_sms_id'] = $createdSms->id ?? null;
$this->log([
'twilio_sms_id' => $createdSms->id ?? null,
'sms_sid' => $result['data']['sid'] ?? null,
'event' => 'send_sms_request',
'new_status' => $result['data']['status'] ?? null,
'details' => $result['data'],
]);
}catch(Exception $ex){
$result['success'] = false;
$result['message'] = $ex->getMessage();
$result['data']['error_message'] = $result['message'];
$this->log([
'twilio_sms_id' => null,
'sms_sid' => $result['data']['sid'] ?? null,
'event' => 'send_sms_request_error',
'new_status' => $result['data']['status'] ?? null,
'details' => $result['data'] ?? [],
]);
}
return $result;
}
private function log($data) {
try {
if(empty($data)) {
throw new Exception('Invalid log data');
}
$logData = [
'twilio_sms_id' => $data['twilio_sms_id'] ?? null,
'sms_sid' => $data['sms_sid'] ?? null,
'sms_message_sid' => $data['sms_sid'] ?? null,
'event' => $data['event'] ?? 'generic_error',
'new_status' => $data['new_status'] ?? null,
'details' => json_encode(($data['details'] ?? [])),
];
TwilioSmsLog::create($logData);
}catch (Exception $ex) {
// NOTICE: Should probably create a log channel just for Twilio
Log::channel('single')->error($ex->getFile().' :: '.$ex->getLine().' :: '.$ex->getMessage());
}
}
/**
* Get Twilio Client
* @return Client
*/
public function getClient(){
return $this->client;
}
}



Now every time we make a sendMessage request the following will happen:

  • Add callback URL to sendMessage request.
  • If the request was successful create TwilioSms record on DB.
  • Create TwilioSmsLog.

Newly created messages.

New messages are created with status queued

And the log table.

Created log for send_sms event, associated with twilio_sms and current status

4. Handle Twilio Status Changed Request.

Add statusChanged Method to TwilioSmsController. The logic is just an example of implementation. You can make any adjustment as long as you return response([‘success’ => true], 200).

In summary, we log every request and if we can match the request with an SMS in our application and the request status is different from the current TwilioSms status we update it.

TwilioSmsController with status changed method:

<?php
namespace App\Http\Controllers;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Models\TwilioSms;
use App\Models\TwilioSmsLog;
class TwilioSmsController extends Controller
{
/**
* This function is a public exposed route that handles twilio requests (from twilio) to inform status changes from messages
* Format application/x-www-form-urlencoded
* Method POST
* Request parameters
* SmsSid: SM2xxxxxx
* SmsStatus: sent
* Body: McAvoy or Stewart? These timelines can get so confusing.
* MessageStatus: sent
* To: +1512zzzyyyy
* MessageSid: SM2xxxxxx
* AccountSid: ACxxxxxxx
* From: +1512xxxyyyy
* ApiVersion: 2010-04-01
*/
public function statusChanged(Request $request) {
// Create log
try{
$logData = [
'sms_sid' => $request['SmsSid'] ?? null,
'sms_message_sid' => $request['MessageSid'] ?? null,
'twilio_sms_id' => null,
'event' => 'not_categorized',
'new_status' => $request['MessageStatus'] ?? null,
'details' => json_encode(($request->all() ?? [])),
];
try {
if(!isset($request['SmsSid'])) {
$logData['event'] = 'invalid_request_sid_not_defined';
throw new Exception('Sid not defined. Could not match with system sms.');
}
$twilioSms = TwilioSms::select('id', 'sid', 'status')->where('sid', $request['SmsSid'])->first();
if(empty($twilioSms->id)) {
$logData['event'] = 'twilio_sms_not_found';
throw new Exception('Twilio sms sid: '.$request['SmsSid'].' was not found.');
}
$logData['twilio_sms_id'] = $twilioSms->id;
$logData['event'] = 'partial_status_changed';
if(isset($request['SmsStatus']) && $twilioSms->status != $request['SmsStatus']) {
$logData['event'] = 'status_changed';
$twilioSms->status = $request['SmsStatus'];
$twilioSms->save();
}
}catch(Exception $ex2) {
Log::channel('twilio')->error($ex2->getFile().' :: '.$ex2->getMessage());
}
TwilioSmsLog::create($logData);
}catch(Exception $ex) {
Log::channel('twilio')->error($ex->getFile().' :: '.$ex->getMessage().' :: '.json_encode(($request->all() ?? [])));
}
return response(['success' => true], 200);
}
/**
* Test sms send
* @return mixed
*/
public function sendTest(Request $request) {
try {
// Make sure it is E.164 formatting
$toPhoneNumber = 'TO_PHONE_NUMBER_YOU_ARE_TESTING';
$sendResult = app('TwilioService')->sendMessage($toPhoneNumber, 'Hi, this is a test');
if(!isset($sendResult['success']) || !$sendResult['success']) {
throw new Exception(($sendResult['message'] ?? ''));
}
return $sendResult;
}catch (Exception $ex) {
return 'Send SMS Failed - '.$ex->getMessage();
}
}
}

With the webhook in place, we will start to see our messages go through different states. It usually just takes a few seconds to go from queued to sent.

It will look like this in the database.

That’s it for it tracking SMS status changes and keeping an updated representation of each Twilio SMS sent by the application. The next step is to receive and store messages.

Receive SMS

  1. Create messageReceived method on TwilioSmsController.

TwilioSmsController final version:

<?php
namespace App\Http\Controllers;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Models\TwilioSms;
use App\Models\TwilioSmsLog;
class TwilioSmsController extends Controller
{
/**
* This function is a public exposed route that handles twilio requests (from twilio) to inform status changes from messages
* Format application/x-www-form-urlencoded
* Method POST
* Request parameters
* SmsSid: SM2xxxxxx
* SmsStatus: sent
* Body: McAvoy or Stewart? These timelines can get so confusing.
* MessageStatus: sent
* To: +1512zzzyyyy
* MessageSid: SM2xxxxxx
* AccountSid: ACxxxxxxx
* From: +1512xxxyyyy
* ApiVersion: 2010-04-01
*/
public function statusChanged(Request $request) {
try{
$logData = [
'sms_sid' => $request['SmsSid'] ?? null,
'sms_message_sid' => $request['MessageSid'] ?? null,
'twilio_sms_id' => null,
'event' => 'not_categorized',
'new_status' => $request['MessageStatus'] ?? null,
'details' => json_encode(($request->all() ?? [])),
];
try {
if(!isset($request['SmsSid'])) {
$logData['event'] = 'invalid_request_sid_not_defined';
throw new Exception('Sid not defined. Could not match with system sms.');
}
$twilioSms = TwilioSms::select('id', 'sid', 'status')->where('sid', $request['SmsSid'])->first();
if(empty($twilioSms->id)) {
$logData['event'] = 'twilio_sms_not_found';
throw new Exception('Twilio sms sid: '.$request['SmsSid'].' was not found.');
}
$logData['twilio_sms_id'] = $twilioSms->id;
$logData['event'] = 'partial_status_changed';
if(isset($request['SmsStatus']) && $twilioSms->status != $request['SmsStatus']) {
$logData['event'] = 'status_changed';
$twilioSms->status = $request['SmsStatus'];
$twilioSms->save();
}
}catch(Exception $ex2) {
Log::channel('twilio')->error($ex2->getFile().' :: '.$ex2->getMessage());
}
TwilioSmsLog::create($logData);
}catch(Exception $ex) {
Log::channel('twilio')->error($ex->getFile().' :: '.$ex->getMessage().' :: '.json_encode(($request->all() ?? [])));
}
return response(['success' => true], 200);
}
/**
* Handles message_received requests from Twilio
*
* Format application/x-www-form-urlencoded
* Method POST
* Request parameters
* MessageSid A 34 character unique identifier for the message. May be used to later retrieve this message from the REST API.
* SmsSid Same value as MessageSid. Deprecated and included for backward compatibility.
* AccountSid The 34 character id of the Account this message is associated with.
* MessagingServiceSid The 34 character id of the Messaging Service associated with the message.
* From The phone number or Channel address that sent this message.
* To The phone number or Channel address of the recipient.
* Body The text body of the message. Up to 1600 characters long.
* NumMedia The number of media items associated with your message
* Observations:
* All phone numbers in requests from Twilio are in E.164 format if possible. For example, (415) 555-4345 would come through as '+14155554345'. However, there are occasionally cases where Twilio cannot normalize an incoming caller ID to E.164. In these situations, Twilio will report the raw caller ID string.
*/
public function messageReceived(Request $request) {
try{
$logData = [
'sms_sid' => $request['SmsSid'] ?? null,
'sms_message_sid' => $request['MessageSid'] ?? null,
'twilio_sms_id' => null,
'event' => 'not_categorized',
'details' => json_encode(($request->all() ?? [])),
];
if(!empty($request['SmsSid'])) {
$logData['event'] = 'message_received';
$logData['new_status'] = 'received';
$created = TwilioSms::create([
'sid' => $request['SmsSid'] ?? '',
'direction' => 'received',
'from' => $request['From'] ?? '',
'to' => $request['To'] ?? '',
'status' => $request['SmsStatus'] ?? 'error',
'body' => $request['Body'] ?? ''
]);
if(!empty($created->id)) {
$logData['twilio_sms_id'] = $created->id;
}
}
TwilioSmsLog::create($logData);
}catch(Exception $ex) {
Log::channel('twilio')->error($ex->getFile().' :: '.$ex->getMessage().' :: '.json_encode(($request->all() ?? [])));
}
// Proper TwiML Empty response (Do not auto reply SMS)
return response('<Response></Response>', 200)->header('Content-Type', 'text/html');
}
/**
* Test sms send
* @return mixed
*/
public function sendTest(Request $request) {
try {
// Make sure it is E.164 formatting
$toPhoneNumber = 'TO_PHONE_NUMBER';
$sendResult = app('TwilioService')->sendMessage($toPhoneNumber, 'Hi, this is a test');
if(!isset($sendResult['success']) || !$sendResult['success']) {
throw new Exception(($sendResult['message'] ?? ''));
}
return $sendResult;
}catch (Exception $ex) {
return 'Send SMS Failed - '.$ex->getMessage();
}
}
}

2. Add webhook route.

....../*** Twilio message received webhook* is-twilio-request middleware makes sure only twilio has access to this route*/Route::any('/twilio/webhook/message-received', [TwilioSmsController::class, 'messageReceived'])->middleware(['is-twilio-request'])->name('api.twilio.message-received');...
...

3. Add webhook URL to a phone number in Twilio console.

Find your phone number details page on the Twilio console.

Click on the phone number you want to manage and then find the Messaging section on the details page. Here you can define a “message comes in” action. Select webhook and input your webhook URL.

Save and you are all set to start receiving SMS in your application.

Whenever a message comes in we are going to create a TwilioSms record and a TwilioSmsLog record.

Conclusion

We accomplished:

✅ Send SMS.

✅ Track Sent SMS Status.

✅ Keep local updated representation of a Twilio SMS.

✅ Every time a Twilio phone receives a message we get it and store it.

Possible gotchas:

  • Test with phone numbers in E.164 formatting.
  • Trial phone numbers can only send messages to verified numbers.
  • Sometimes sending a message to a region is disabled, so you have to enable the region on the Twilio console.
  • Webhook URL must be publicly accessible. No auth. Not behind a server configuration restriction.

I hope this article was helpful.

If you have any feedback or found mistakes, please don’t hesitate to reach out to me.






Post a Comment

أحدث أقدم