Laravel Fast2SMS

Laravel Fast2SMS v2.0.0 — WhatsApp Support, Notification Channels & a Smarter DX

Reading Time: 4 minutes

When I shipped v1 of laravel fast2sms, the goal was simple: send SMS to Indian phone numbers from Laravel without wrestling raw API arrays. v2.0.0 takes that same idea much further.

Laravel Fast2SMS

The headline is WhatsApp Business API support — text, images, documents, locations, templates, reactions, stickers, and interactive messages, all through the same familiar Fast2sms facade. Beyond that, v2 brings drop-in Laravel Notification Channels, a typed exception hierarchy, expressive testing utilities, and cost-saving guards that protect your wallet in production.

⚠️ This is a major release with breaking changes. See the Upgrade Guide before updating.

Let me walk you through what matters.


What this package actually does

At its core, this package acts as a thin Laravel-friendly layer over the Fast2SMS API.

Instead of manually crafting HTTP requests, handling headers, parsing responses, and managing failures — you interact with a clean, expressive API that feels native to Laravel.

It doesn’t replace Fast2SMS. It simplifies how you use it.

How this saves you time

A typical Fast2SMS integration involves:

  • Writing raw HTTP requests
  • Managing authentication headers
  • Handling retries and failures
  • Structuring payloads correctly (DLT, variables, etc.)
  • Helps prevent unnecessary SMS usage and cost

This package removes that repetitive setup.

In most cases, what takes 1–2 hours of setup can be reduced to a few minutes with a single method call.

WhatsApp Business API

This is the big one. Starting in v2.0.0, the package supports the Fast2SMS WhatsApp Business API through Fast2sms::whatsapp().

Send a plain text message:

use Shakil\Fast2sms\Facades\Fast2sms;

Fast2sms::whatsapp()
    ->to('9999999999')
    ->text('Your order has been shipped and is on its way!')
    ->send();

Send an image with a caption:

Fast2sms::whatsApp()
    ->to('9999999999')
    ->image('https://yourapp.com/invoice.png', caption: 'Your invoice for order #1042')
    ->send();

Send a document:

Fast2sms::whatsApp()
    ->to('9999999999')
    ->document('https://yourapp.com/receipt.pdf', filename: 'receipt.pdf')
    ->send();

Send a location:

Fast2sms::whatsApp()
    ->to('9999999999')
    ->location(lat: 28.6139, lng: 77.2090, name: 'New Delhi')
    ->send();

Send a registered template:

Fast2sms::whatsApp()
    ->to('9999999999')
    ->template(id: 'YOUR_TEMPLATE_ID', variables: ['John', 'Order #1042'])
    ->send();

React to a message, send a sticker, or build interactive button flows — the full WhatsApp API surface is available through the same fluent chain.


Laravel Notification Channels

v2 ships two drop-in notification channels: SmsChannel and WhatsAppChannel. Your existing notification classes work exactly the way you’d expect.

use Shakil\Fast2sms\Channels\SmsChannel;
use Shakil\Fast2sms\Channels\WhatsAppChannel;
use Shakil\Fast2sms\Messages\SmsMessage;
use Shakil\Fast2sms\Messages\WhatsAppMessage;

class OrderShipped extends Notification
{
    public function via($notifiable): array
    {
        return [SmsChannel::class, WhatsAppChannel::class];
    }

    public function toFast2sms($notifiable): SmsMessage
    {
        return SmsMessage::create()
            ->otp('Your OTP is 482910. Valid for 10 minutes.');
    }

    public function toWhatsApp($notifiable): WhatsAppMessage
    {
        return WhatsAppMessage::create()
            ->text('Your order has been shipped!');
    }
}

Add the routing methods to your User model and you’re done:

public function routeNotificationForFast2sms(): string
{
    return $this->phone_number;
}

public function routeNotificationForWhatsapp(): string
{
    return $this->phone_number;
}

No facade, no manual number passing. Just idiomatic Laravel.


Typed Exception Hierarchy

In v1, every API failure threw a single Fast2smsException. In v2 you can catch exactly what you need:

use Shakil\Fast2sms\Exceptions\AuthenticationException;
use Shakil\Fast2sms\Exceptions\RateLimitException;
use Shakil\Fast2sms\Exceptions\InsufficientBalanceException;
use Shakil\Fast2sms\Exceptions\NetworkException;

try {
    Fast2sms::otp('9999999999', '845621');
} catch (InsufficientBalanceException $e) {
    // Notify your team — wallet is empty
} catch (RateLimitException $e) {
    // Back off and retry
} catch (AuthenticationException $e) {
    // API key is wrong or expired
} catch (NetworkException $e) {
    // Fast2SMS was unreachable
}

The full list of typed exceptions is in the changelog.


Rich Fake Assertions for Testing

v2 ships 16 assertion methods on Fast2smsFake so your feature tests are expressive and readable — no more inspecting raw recorded calls.

Fast2sms::fake();

// ... trigger your code ...

Fast2sms::assertSmsSentTo('9999999999');

Fast2sms::assertSmsSentTo('9999999999', fn ($sms) =>
    str_contains($sms->message, '482910')
);

Fast2sms::assertWhatsAppSentTo('9999999999');

Fast2sms::assertNothingSent();

// Clean up for tests that need real sending
Fast2sms::stopFaking();

Fluent Message Builders with Credit Helpers

SmsMessage and WhatsAppMessage are first-class objects with named constructors and chainable setters. SmsMessage also ships with credit helpers so you can estimate cost before you send:

use Shakil\Fast2sms\Messages\SmsMessage;

$message = SmsMessage::create()
    ->withContent('Your appointment is confirmed for tomorrow at 10am.')
    ->withRoute(SmsRoute::QUICK);

$message->charCount();       // character count
$message->isUnicode();       // true if Unicode encoding is needed
$message->creditCount();     // SMS credits this will consume
$message->exceedsOneSms();   // true if longer than one SMS

No more guessing whether a long message costs 1 credit or 3.


Built-in safeguards to avoid wasted SMS costs

In real-world apps, SMS costs often increase due to small mistakes like duplicate sends, invalid numbers, or retry issues.

This release includes a few optional safeguards that protect your wallet in production.:

  • Removes duplicate numbers automatically (enabled by default)
  • Filters out invalid recipients before sending
  • Prevents duplicate sends within a short time window
  • Allows rate limiting to avoid over-sending
  • Checks wallet balance before sending
  • Lets you estimate SMS credits before sending

These are simple additions, but they help keep costs under control as your application scales.

New Artisan Commands

# List every event the package fires, with descriptions
php artisan fast2sms:events

# Generate an IDE helper file for full autocompletion
php artisan fast2sms:ide-helper

Run fast2sms:ide-helper once after install and get full autocompletion on every facade method in PhpStorm or VS Code.


Getting Started

Requirements: PHP ^8.3 (8.4 and 8.5 also tested), Laravel 11, 12, or 13.

composer require itxshakil/laravel-fast2sms
php artisan vendor:publish --tag=fast2sms-config
FAST2SMS_API_KEY="your-api-key"
FAST2SMS_DEFAULT_SENDER_ID="FSTSMS"
FAST2SMS_DEFAULT_ROUTE="dlt"

Upgrading from v1

The public sending API — Fast2sms::quick()::dlt()::otp(), and now ::viaWhatsApp() — is completely unchanged. Most v1 code will work without modification.

The breaking changes are in internals: exception types, DTOs, and return type hints. The full step-by-step migration is in UPGRADING.md.


If this saved you time, a star on GitHub helps other Laravel developers find the package.

If you’re already using Fast2SMS in a Laravel project, this package can simplify your integration and make your code easier to manage as your application grows.

You can get started in just a few minutes.


Built by Shakil Alam — Laravel developer, open-source contributor.

Laravel Fast2SMS v2.0.0 — WhatsApp Support, Notification Channels & a Smarter DX

Oh hi there 👋
It’s nice to meet you.

Sign up to receive awesome content in your inbox.

We don’t spam! Read our privacy policy for more info.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.