sudiptpa / laravel-sent-dm
An expressive Laravel adapter for the Sent.dm unified messaging API: SMS, WhatsApp and RCS with a fluent, elegant interface.
Fund package maintenance!
Requires
- php: ^8.2
- illuminate/bus: ^11.0|^12.0|^13.0
- illuminate/cache: ^11.0|^12.0|^13.0
- illuminate/console: ^11.0|^12.0|^13.0
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/events: ^11.0|^12.0|^13.0
- illuminate/http: ^11.0|^12.0|^13.0
- illuminate/notifications: ^11.0|^12.0|^13.0
- illuminate/queue: ^11.0|^12.0|^13.0
- illuminate/routing: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
- sentdm/sent-dm-php: ^0.36
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.0
- mockery/mockery: ^1.6
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.0
- phpstan/extension-installer: ^1.0
- phpstan/phpstan: ^2.0
- phpstan/phpstan-deprecation-rules: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-03 14:59:11 UTC
README
A Laravel integration for Sent.dm, the unified messaging API for SMS, WhatsApp, and RCS.
This package wraps the official sentdm/sent-dm-php SDK with Laravel features for sending messages, queueing jobs, notification channels, handling webhooks, logging delivery state, managing opt-outs, scoping organization profiles, and testing without real API calls.
All HTTP transport goes through the official SDK. Sender profiles, compliance, and non-voice channel setup use the SDK client's request method until the SDK adds named methods for those endpoints.
What this package handles
- Immediate or queued sends:
send()sends now;sendLater()dispatches a job. - MMS and scheduled sends: attach media, add a subject, or schedule delivery.
- Auto-channel routing: Sent.dm chooses WhatsApp or SMS based on reachability.
- Webhook signature verification: HMAC-SHA256 checked before handlers run.
- Voice calls: manage voice numbers, app tokens, calls, and participants.
- Idempotent deduplication: retried webhook events do not fire listeners twice.
- Rate limit handling: queued sends retry after the API's
Retry-Afterdelay. - Caching: caches contacts, profiles, number lookups, and template names.
- Multi-tenancy: switch accounts with
Sent::connection(). - Organization profile scoping: scope resource calls with
->profile($id). - Message log: records queued sends and syncs webhook delivery status.
- Opt-out compliance: handles STOP/UNSTOP and can guard opted-out sends.
- Testing:
Sent::fake()gives assertions without real API calls.
What stays in your application
These choices stay in your application:
- When to send: decide timing in your own business logic.
- Template content: create and manage templates in the Sent.dm dashboard.
- Campaign scheduling: use Laravel's
schedule()to dispatch bulk sends. - Analytics UI: build dashboards from your own data, such as
$user->sentMessages(). - Contact imports: sync from your database with
Sent::contacts()->create()in a job or command. - Custom retry strategies: listen to
MessageFailedand re-dispatch with your own rules. - Per-user notification preferences: check
$user->optedOutFromSent()before sending.
Requirements
- PHP 8.2+ for Laravel 11 and 12
- PHP 8.3+ for Laravel 13
- Laravel 11, 12, or 13
Installation
composer require sudiptpa/laravel-sent-dm
Publish the config file:
php artisan sent:install
Add your API key to .env:
SENT_API_KEY=your-api-key
Verify the connection and local package configuration:
php artisan sent:health
See the upgrade guide before updating an existing installation.
Configuration
The published config is at config/sent.php:
'default' => env('SENT_CONNECTION', 'default'), 'connections' => [ 'default' => [ 'api_key' => env('SENT_API_KEY'), ], ], 'default_channel' => env('SENT_DEFAULT_CHANNEL'), // null = auto-route 'queue' => [ 'connection' => env('SENT_QUEUE_CONNECTION'), 'name' => env('SENT_QUEUE_NAME', 'default'), ], 'webhook' => [ 'enabled' => env('SENT_WEBHOOK_ENABLED', false), 'secret' => env('SENT_WEBHOOK_SECRET'), 'path' => env('SENT_WEBHOOK_PATH', 'sent/webhook'), ], 'cache' => [ 'enabled' => env('SENT_CACHE_ENABLED', true), 'ttl' => env('SENT_CACHE_TTL', 3600), ], 'sandbox' => env('SENT_SANDBOX', false), 'logging' => [ 'enabled' => env('SENT_LOGGING_ENABLED', false), ], 'opt_out' => [ 'enabled' => env('SENT_OPT_OUT_ENABLED', false), 'guard' => env('SENT_OPT_OUT_GUARD', false), 'tenant_resolver' => null, // optional tenant-aware opt-out resolver 'keywords' => ['STOP', 'UNSUBSCRIBE', 'CANCEL', 'END', 'QUIT'], 'opt_in_keywords' => ['START', 'YES', 'UNSTOP'], ],
Quick start
use Sujip\SentDm\Facades\Sent; Sent::to('+61412345678') ->template('otp-verification') ->send();
This sends immediately. For queued sends, plain-text bodies, channel selection, template variables, and bulk sends, see Sending messages.
Documentation
| Guide | Covers |
|---|---|
| Sending messages | Immediate and queued sends, template variables, idempotency, bulk messaging, the notification channel |
| Sandbox mode | Simulating writes without real delivery, per-call and globally |
| Webhooks | Receiving delivery events, signature verification, managing endpoints from code |
| Message log | The opt-in sent_logs table, HasSentMessages, query scopes, status tracking |
| Opt-out management | STOP/START keyword handling, tenant-aware opt-outs, HasSentContact, the send guard |
| Multi-tenancy | Organization profile scoping and multiple Sent.dm connections |
| Number lookup and validation | Carrier lookup and the sentMobileNumber validation rule |
| API reference | Contacts, Templates, Profiles, Users, Messages, Conversations, Account, Artisan commands |
| Testing | Sent::fake() and its full assertion set |
Sponsoring
If this package helps your project, GitHub Sponsors is a simple way to support maintenance and future releases.
Contributing
Contributions are welcome. Open an issue to discuss larger changes, or send a pull request for bug fixes and small improvements.
Before submitting, run:
composer test
composer stan
composer lint:check
License
This package is open source, licensed under the MIT license.