PHPackages                             ratoufa/laravel-messaging - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Mail &amp; Notifications](/categories/mail)
4. /
5. ratoufa/laravel-messaging

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

ratoufa/laravel-messaging
=========================

Multi-channel messaging for Laravel (SMS via AfrikSMS, WhatsApp via Twilio)

v0.2.0(4mo ago)03[2 PRs](https://github.com/Ratoufa/laravel-messaging-pakcage/pulls)MITPHPPHP ^8.4CI passing

Since Dec 25Pushed 1mo agoCompare

[ Source](https://github.com/Ratoufa/laravel-messaging-pakcage)[ Packagist](https://packagist.org/packages/ratoufa/laravel-messaging)[ Docs](https://github.com/Ratoufa/laravel-messaging-pakcage)[ GitHub Sponsors](https://github.com/Ratoufa)[ RSS](/packages/ratoufa-laravel-messaging/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (17)Versions (6)Used By (0)

Laravel Messaging
=================

[](#laravel-messaging)

[![Latest Version on Packagist](https://camo.githubusercontent.com/e82e1789e5e967f338adf067279c796e6015be2909235081aa75fac3fd24b097/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7261746f7566612f6c61726176656c2d6d6573736167696e672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/ratoufa/laravel-messaging)[![GitHub Tests Action Status](https://camo.githubusercontent.com/e7e16ee644798321c593f1b7e9b07698e473a26fff7148430ccb7d8497da1657/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7261746f7566612f6c61726176656c2d6d6573736167696e672f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/ratoufa/laravel-messaging/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/853e3a18def6c207485a875c8decd26dbf37db6f4dbe4ee445e3ecc62caf803e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7261746f7566612f6c61726176656c2d6d6573736167696e672f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/ratoufa/laravel-messaging/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/98e14c9b17e14bebaebfd99f6233fa330abdafea67d652eea37651a93c3519c8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7261746f7566612f6c61726176656c2d6d6573736167696e672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/ratoufa/laravel-messaging)

A multi-channel messaging package for Laravel supporting SMS (via AfrikSMS) and WhatsApp (via Twilio). Features a fluent API, OTP verification, Laravel Notifications integration, and extensible gateway system.

Requirements
------------

[](#requirements)

- PHP 8.4+
- Laravel 11.x or 12.x

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require ratoufa/laravel-messaging
```

Publish the configuration file:

```
php artisan vendor:publish --tag="messaging-config"
```

Configuration
-------------

[](#configuration)

Add the following environment variables to your `.env` file:

```
# Default channel (sms or whatsapp)
MESSAGING_DEFAULT_CHANNEL=sms

# AfrikSMS credentials
AFRIKSMS_CLIENT_ID=your-client-id
AFRIKSMS_API_KEY=your-api-key
AFRIKSMS_SENDER_ID=MyApp

# Twilio WhatsApp credentials
TWILIO_SID=your-account-sid
TWILIO_AUTH_TOKEN=your-auth-token
TWILIO_WHATSAPP_FROM=whatsapp:+15551234567

# OTP settings (optional)
MESSAGING_OTP_LENGTH=6
MESSAGING_OTP_EXPIRY=10
MESSAGING_OTP_MAX_ATTEMPTS=3

# Phone formatting (optional)
MESSAGING_DEFAULT_COUNTRY_CODE=228
```

Usage
-----

[](#usage)

### SMS

[](#sms)

#### Send a single SMS

[](#send-a-single-sms)

```
use Ratoufa\Messaging\Facades\Sms;

// Fluent API
$response = Sms::to('22890123456')->send('Hello World!');

// With custom sender ID
$response = Sms::to('22890123456')
    ->from('MyBrand')
    ->send('Hello World!');

// Using a message object
use Ratoufa\Messaging\Data\SmsMessage;

$message = new SmsMessage(
    recipient: '22890123456',
    content: 'Hello World!',
    senderId: 'MyBrand',
);

$response = Sms::send($message);
```

#### Send bulk SMS

[](#send-bulk-sms)

```
use Ratoufa\Messaging\Facades\Sms;

// Fluent API - same message to multiple recipients
$response = Sms::toMany(['22890123456', '22891234567'])
    ->send('Bulk message to all');

// Using a message object
use Ratoufa\Messaging\Data\BulkMessage;

$message = new BulkMessage(
    recipients: ['22890123456', '22891234567'],
    content: 'Bulk message to all',
    senderId: 'MyBrand',
);

$response = Sms::sendBulk($message);
```

#### Send personalized SMS

[](#send-personalized-sms)

```
use Ratoufa\Messaging\Facades\Sms;
use Ratoufa\Messaging\Data\PersonalizedMessage;

$messages = [
    new PersonalizedMessage('22890123456', 'Hello John, your code is 1234'),
    new PersonalizedMessage('22891234567', 'Hello Jane, your code is 5678'),
];

$response = Sms::sendPersonalized($messages);
```

#### Check balance

[](#check-balance)

```
use Ratoufa\Messaging\Facades\Sms;

$balances = Sms::getBalance();

foreach ($balances as $balance) {
    echo "{$balance->country}: {$balance->balance} credits";
}
```

#### Configure delivery callback

[](#configure-delivery-callback)

```
use Ratoufa\Messaging\Facades\Sms;

// POST callback (default)
$response = Sms::configureCallback('https://example.com/webhook/sms');

// GET callback
$response = Sms::configureCallback('https://example.com/webhook/sms', 'GET');
```

### WhatsApp

[](#whatsapp)

#### Send a message

[](#send-a-message)

```
use Ratoufa\Messaging\Facades\WhatsApp;

// Simple message
$response = WhatsApp::to('22890123456')->send('Hello via WhatsApp!');

// Using a message object
use Ratoufa\Messaging\Data\SmsMessage;

$message = new SmsMessage(
    recipient: '22890123456',
    content: 'Hello via WhatsApp!',
);

$response = WhatsApp::send($message);
```

#### Send a template message

[](#send-a-template-message)

```
use Ratoufa\Messaging\Facades\WhatsApp;

$response = WhatsApp::sendTemplate(
    recipient: '22890123456',
    contentSid: 'HXb5a34a7e18eb123456789',
    variables: ['1' => 'John', '2' => 'Order #12345'],
);
```

#### Send media

[](#send-media)

```
use Ratoufa\Messaging\Facades\WhatsApp;

// Image with caption
$response = WhatsApp::sendMedia(
    recipient: '22890123456',
    mediaUrl: 'https://example.com/image.jpg',
    caption: 'Check this out!',
);

// Document without caption
$response = WhatsApp::sendMedia(
    recipient: '22890123456',
    mediaUrl: 'https://example.com/document.pdf',
);
```

#### Using the fluent API with templates

[](#using-the-fluent-api-with-templates)

> **Note:** WhatsApp has a 24-hour messaging window. You can send freeform messages only within 24 hours after the user's last reply. After that, you must use a pre-approved Message Template.

```
use Ratoufa\Messaging\Facades\WhatsApp;

// Fluent template with variables
$response = WhatsApp::to('22890123456')
    ->template('HXb5a34a7e18eb123456789', ['1' => 'John', '2' => 'Order #12345'])
    ->send();

// Template without variables
$response = WhatsApp::to('22890123456')
    ->template('HXb5a34a7e18eb123456789')
    ->send();

// Fluent media with caption
$response = WhatsApp::to('22890123456')
    ->media('https://example.com/image.jpg')
    ->send('Check this out!');
```

### OTP Verification

[](#otp-verification)

#### Send OTP

[](#send-otp)

```
use Ratoufa\Messaging\Facades\Otp;

$result = Otp::send('22890123456');

if ($result->success) {
    echo "OTP sent, expires at: {$result->expiresAt}";
}

// With custom purpose
$result = Otp::send('22890123456', 'password-reset');
```

#### Verify OTP

[](#verify-otp)

```
use Ratoufa\Messaging\Facades\Otp;

$isValid = Otp::verify('22890123456', '123456');

if ($isValid) {
    echo "OTP verified successfully!";
}

// With custom purpose
$isValid = Otp::verify('22890123456', '123456', 'password-reset');
```

#### Resend OTP

[](#resend-otp)

```
use Ratoufa\Messaging\Facades\Otp;

$result = Otp::resend('22890123456');
```

#### Check remaining attempts

[](#check-remaining-attempts)

```
use Ratoufa\Messaging\Facades\Otp;

$attempts = Otp::remainingAttempts('22890123456');
echo "Remaining attempts: {$attempts}";
```

#### Invalidate OTP

[](#invalidate-otp)

```
use Ratoufa\Messaging\Facades\Otp;

Otp::invalidate('22890123456');
```

#### Send OTP via WhatsApp

[](#send-otp-via-whatsapp)

> **Note:** WhatsApp OTP uses a pre-approved Message Template to ensure delivery even outside the 24-hour messaging window. You must configure the template SID in your `.env` file.

```
TWILIO_OTP_TEMPLATE_SID=HXxxxxxxxxxxxxxxxxx
TWILIO_OTP_CODE_VARIABLE=1
```

```
use Ratoufa\Messaging\Facades\Otp;

// Send OTP via WhatsApp (uses template)
$result = Otp::whatsapp()->send('22890123456');

// Verify OTP (same as SMS)
$isValid = Otp::whatsapp()->verify('22890123456', '123456');

// Resend OTP via WhatsApp
$result = Otp::whatsapp()->resend('22890123456');
```

### Using the Messaging Facade

[](#using-the-messaging-facade)

The `Messaging` facade provides access to all channels:

```
use Ratoufa\Messaging\Facades\Messaging;

// SMS
Messaging::sms()->to('22890123456')->send('Hello!');

// WhatsApp
Messaging::whatsapp()->to('22890123456')->send('Hello!');

// OTP
Messaging::otp()->send('22890123456');

// Dynamic channel selection
Messaging::channel('sms')->to('22890123456')->send('Hello!');
```

### Response Handling

[](#response-handling)

All send operations return a `Response` object:

```
use Ratoufa\Messaging\Facades\Sms;
use Ratoufa\Messaging\Enums\ResponseCode;

$response = Sms::to('22890123456')->send('Hello!');

// Check success
if ($response->success) {
    echo "Message sent! ID: {$response->resourceId}";
}

// Check specific error codes
if ($response->code === ResponseCode::INSUFFICIENT_BALANCE) {
    echo "Please recharge your account";
}

// Available response codes
ResponseCode::SUCCESS              // 100
ResponseCode::INVALID_CREDENTIALS  // 401
ResponseCode::INSUFFICIENT_BALANCE // 402
ResponseCode::INVALID_RECIPIENT    // 422
ResponseCode::TEMPLATE_REQUIRED    // 463 (WhatsApp 24h window expired)
ResponseCode::SERVER_ERROR         // 500
```

Laravel Notifications
---------------------

[](#laravel-notifications)

### SMS Channel

[](#sms-channel)

```
use Illuminate\Notifications\Notification;
use Ratoufa\Messaging\Data\SmsMessage;

class OrderShipped extends Notification
{
    public function via($notifiable): array
    {
        return ['sms'];
    }

    public function toSms($notifiable): SmsMessage
    {
        return new SmsMessage(
            recipient: $notifiable->phone,
            content: "Your order #{$this->order->id} has been shipped!",
        );
    }
}
```

### WhatsApp Channel

[](#whatsapp-channel)

```
use Illuminate\Notifications\Notification;
use Ratoufa\Messaging\Data\SmsMessage;

class OrderShipped extends Notification
{
    public function via($notifiable): array
    {
        return ['whatsapp'];
    }

    public function toWhatsApp($notifiable): SmsMessage
    {
        return new SmsMessage(
            recipient: $notifiable->phone,
            content: "Your order #{$this->order->id} has been shipped!",
        );
    }
}
```

### Model Trait

[](#model-trait)

Add the `HasMessaging` trait to your model for quick messaging:

```
use Ratoufa\Messaging\Concerns\HasMessaging;

class User extends Authenticatable
{
    use HasMessaging;

    // Define the phone field (defaults to 'phone')
    public function routeNotificationForSms(): ?string
    {
        return $this->phone_number;
    }

    public function routeNotificationForWhatsApp(): ?string
    {
        return $this->whatsapp_number;
    }
}
```

Usage:

```
$user->sendSms('Hello!');
$user->sendWhatsApp('Hello via WhatsApp!');
$user->sendOtp();
$user->verifyOtp('123456');
```

Custom Gateways
---------------

[](#custom-gateways)

You can register custom gateways:

```
use Ratoufa\Messaging\Contracts\GatewayInterface;
use Ratoufa\Messaging\Facades\Messaging;

class MyCustomGateway implements GatewayInterface
{
    public function send(SmsMessage $message): Response
    {
        // Your implementation
    }

    public function getBalance(): Collection
    {
        // Your implementation
    }
}

// Register the gateway
Messaging::extend('custom', new MyCustomGateway());

// Use it
Messaging::channel('custom')->to('22890123456')->send('Hello!');
```

Artisan Command
---------------

[](#artisan-command)

Check your account balance:

```
php artisan messaging balance
php artisan messaging balance --channel=whatsapp
```

Phone Number Formatting
-----------------------

[](#phone-number-formatting)

The package includes a phone formatter utility:

```
use Ratoufa\Messaging\Support\PhoneFormatter;

$formatter = new PhoneFormatter();

// Format with default country code (from config)
$phone = $formatter->format('90123456'); // "22890123456"

// Format with specific country code
$phone = $formatter->format('90123456', '229'); // "22990123456"

// Format for WhatsApp
$phone = $formatter->formatForWhatsApp('22890123456'); // "whatsapp:+22890123456"

// Format multiple numbers
$phones = $formatter->formatMany(['90123456', '91234567']);

// Validate phone number
$isValid = $formatter->isValid('22890123456'); // true
```

Events
------

[](#events)

The package dispatches events for delivery reports:

```
use Ratoufa\Messaging\Events\MessageDeliveryReportReceived;

class MessageDeliveryListener
{
    public function handle(MessageDeliveryReportReceived $event): void
    {
        $messageId = $event->messageId;
        $status = $event->status; // DeliveryStatus enum
        $recipient = $event->recipient;
        $deliveredAt = $event->deliveredAt;
    }
}
```

Register in `EventServiceProvider`:

```
protected $listen = [
    MessageDeliveryReportReceived::class => [
        MessageDeliveryListener::class,
    ],
];
```

Testing
-------

[](#testing)

```
composer test
```

This runs:

- PHPStan (static analysis)
- Pest (unit &amp; feature tests)
- Pint (code style)
- Rector (refactoring checks)
- Peck (typo detection)

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Just Chris](https://github.com/justchr1s)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance85

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 66.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

135d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4db3528d863e3ddfd5f5e220f66bed7cfe979e617fab84bfeaa6bc148e0c893e?d=identicon)[justchris](/maintainers/justchris)

---

Top Contributors

[![justchr1s](https://avatars.githubusercontent.com/u/62968995?v=4)](https://github.com/justchr1s "justchr1s (4 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

africaafriksmslaravelnotificationsotpsmstogotwiliowhatsapplaravelotpnotificationssmstwiliowhatsappafricaafriksmstogo

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/ratoufa-laravel-messaging/health.svg)

```
[![Health](https://phpackages.com/badges/ratoufa-laravel-messaging/health.svg)](https://phpackages.com/packages/ratoufa-laravel-messaging)
```

###  Alternatives

[laravel-notification-channels/twilio

Provides Twilio notification channel for Laravel

2587.7M12](/packages/laravel-notification-channels-twilio)[vormkracht10/laravel-mails

Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.

24149.7k](/packages/vormkracht10-laravel-mails)[simplesoftwareio/simple-sms

Simple-SMS is a package made for Laravel to send/receive (polling/pushing) text messages. Currently supports CalLFire, EZTexting, Email Gateways, FlowRoute, LabsMobile, Mozeo, Nexmo, Plivo, Twilio, and Zenvia

20845.7k5](/packages/simplesoftwareio-simple-sms)[tomatophp/filament-twilio

Send Whatsapp messages using Twilio and native filament Notification Facade class

112.3k](/packages/tomatophp-filament-twilio)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
