When I shipped v1, 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.
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.
💬 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.
🛡️ Cost-Saving Guards
v2 introduces a set of opt-in guards that protect your wallet in production. All are off by default — enable only what your use case needs in config/fast2sms.php:
| Guard | What it does |
|---|---|
| Recipient deduplication | Strips duplicate numbers before every send |
| Invalid recipient stripping | Validates numbers and logs warnings instead of failing hard |
| Idempotency guard | Blocks the same message being sent twice within a TTL window |
| Rate throttle | Sliding-window per-minute cap via Laravel cache |
| Balance gate | Checks your wallet before sending; fires LowBalanceDetected when low |
| Batch splitting | Splits large recipient lists into chunks automatically |
⚙️ 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.
Links
- ⭐ GitHub: github.com/itxshakil/laravel-fast2sms
- 📦 Packagist: packagist.org/packages/itxshakil/laravel-fast2sms
- 📋 Full Changelog: CHANGELOG.md
- 📖 Upgrade Guide: UPGRADING.md
- 🐛 Issues: github.com/itxshakil/laravel-fast2sms/issues
If this saved you time, a star on GitHub helps other Laravel developers find the package.
Built by Shakil Alam — Laravel developer, open-source contributor.
Top comments (0)