On this page
Overview
Laravel Textify is an SMS layer for Laravel applications. You write Textify::send($number, $message) once and pick the gateway through configuration, so moving from a local provider to Twilio, or running two providers side by side, does not touch your application code.
It ships with drivers for six Bangladeshi gateways and two international ones, plus log and array drivers for local development and tests. Sending can be queued, a fallback provider can take over when the primary one fails, and every send can be recorded for auditing. Textify is built by the DevWizard core team and is MIT licensed.
Features
- One fluent API:
Textify::to()->message()->via()->send(). - Drivers for DhorolaSMS, BulkSMSBD, MimSMS, eSMS, REVE SMS and Alpha SMS (Bangladesh), and Twilio and Vonage (the
nexmodriver). logandarraydrivers for development and automated tests.- Provider fallback: set a second provider with
fallback()and send withsendWithFallback(), which retries on it when the first fails. - Queued sending through a dispatchable job, with an optional queue name.
- A native Laravel notification channel,
textify. - Provider balance checks with
getBalance(). - Lifecycle events:
TextifySending,TextifySent,TextifyFailedandTextifyJobFailed. - Activity tracking to the database or a file, separate from debug logging.
- Configurable message validation (required, minimum and maximum length).
- Custom providers by extending
TextifyProvider.
Requirements
- PHP 8.3 or newer.
- Laravel 10, 11, 12 or 13.
- Guzzle
^7.0or^8.0(installed automatically). - Credentials from at least one supported SMS gateway for production use.
Installation
composer require devwizardhq/laravel-textifyPublish the configuration file:
php artisan vendor:publish --provider="DevWizard\Textify\TextifyServiceProvider" --tag="textify-config"If you want database activity tracking, publish and run the migration:
php artisan textify:table
php artisan migrateConfiguration
Set the default provider in .env. The default is log, which writes messages to your log instead of sending them.
TEXTIFY_PROVIDER=revesmsEach provider has its own block in config/textify.php under providers, driven by environment variables:
| Provider key | Main environment variables |
|---|---|
dhorola |
DHOROLA_API_KEY, DHOROLA_SENDER_ID |
bulksmsbd |
BULKSMSBD_API_KEY, BULKSMSBD_SENDER_ID |
mimsms |
MIMSMS_USERNAME, MIMSMS_APIKEY, MIMSMS_SENDER_ID, MIMSMS_TRANSACTION_TYPE |
esms |
ESMS_API_TOKEN, ESMS_SENDER_ID |
revesms |
REVESMS_APIKEY, REVESMS_SECRETKEY, REVESMS_CLIENT_ID, REVESMS_SENDER_ID |
alphasms |
ALPHASMS_API_KEY, ALPHASMS_SENDER_ID |
twilio |
TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_FROM |
nexmo |
NEXMO_API_KEY, NEXMO_API_SECRET, NEXMO_FROM |
Every HTTP provider also accepts *_TIMEOUT, *_CONNECT_TIMEOUT and *_VERIFY_SSL variables with the provider prefix, for example REVESMS_TIMEOUT.
Other sections of the config file:
activity_tracking.enabled(TEXTIFY_ACTIVITY_TRACKING_ENABLED, defaultfalse) andactivity_tracking.driver(TEXTIFY_ACTIVITY_DRIVER:database,fileornull).logging.enabled,log_successful,log_failedandlog_channelfor debug logging.events.enabled(TEXTIFY_EVENTS_ENABLED) to switch lifecycle events on or off.validation.message.required,minandmaxfor message checks.
Usage
Send a message with the default provider, or name a provider for a single call:
use DevWizard\Textify\Facades\Textify;
Textify::send('01712345678', 'Your verification code is 482913');
Textify::via('revesms')->send('01712345678', 'Sent through REVE SMS');Use the fluent form for multiple recipients or queued delivery:
Textify::to(['01712345678', '01887654321'])
->message('Your order has shipped')
->send();
Textify::to('01712345678')->message('Queued message')->queue('sms');Use it as a notification channel by returning textify from via() and implementing toTextify():
use DevWizard\Textify\Notifications\TextifyMessage;
public function via($notifiable): array
{
return ['textify'];
}
public function toTextify($notifiable): TextifyMessage
{
return TextifyMessage::create('Your order #123 has shipped');
}The channel finds the phone number through routeNotificationForTextify() on the notifiable. Define that method on your User model to return the right attribute.
API Reference
Textify facade
| Method | Description |
|---|---|
send($to = null, $message = null, $from = null) |
Send now; accepts a number, an array of numbers or structured arrays |
to($contacts), message($text), from($sender) |
Prepare a message fluently |
via($driver), driver($driver) |
Choose a provider for this send |
queue($queueName = null) |
Dispatch the prepared message as queued jobs |
fallback($driver) |
Set a fallback provider |
sendWithFallback($to, $message, $from = null) |
Send to one number, retrying on the fallback provider if the first fails |
getBalance($provider = null) |
Provider balance as a float |
getProviders(), hasProvider($name), getProvider($name), getDriver($name = null) |
Inspect registered providers |
reset() |
Clear prepared recipients and message |
Responses and messages
send() returns a TextifyResponse for a single recipient. Useful methods are isSuccessful(), isFailed(), getMessageId(), getErrorMessage(), getErrorCode(), getCost(), getStatus(), getRawResponse() and toArray().
DevWizard\Textify\Notifications\TextifyMessage is a fluent builder with create(), message(), from(), driver() and metadata(). The toTextify() method can also return a plain string or an array.
Provider contract
Custom providers implement TextifyProviderInterface: send(), sendBulk(), getDeliveryStatus(), getBalance(), getName(), supportsCountry(), validatePhoneNumber(), formatPhoneNumber(), getConfig() and setConfig(). Extending TextifyProvider gives you the shared plumbing.
Artisan commands
php artisan textify:test --driver= --to= --message=sends a test message.php artisan textify:tablepublishes the activity migration.
Examples
Send a one-time password and handle a failed result:
$response = Textify::via('revesms')->send($user->phone, "Your OTP is {$otp}");
if ($response->isFailed()) {
report(new RuntimeException($response->getErrorMessage()));
}Send different messages to different recipients in one call:
Textify::send([
['to' => '01712345678', 'message' => 'Welcome aboard'],
['to' => '01887654321', 'message' => 'Your invoice is ready'],
]);Retry on a second gateway when the first one fails:
Textify::via('revesms')->fallback('mimsms')->sendWithFallback('01712345678', 'Your OTP is 482913');Test code that sends SMS without hitting a gateway by selecting the array driver:
TEXTIFY_PROVIDER=arrayReact to delivery outcomes by listening to the package events:
use DevWizard\Textify\Events\TextifyFailed;
Event::listen(TextifyFailed::class, function (TextifyFailed $event) {
Log::warning('SMS failed', ['provider' => $event->provider]);
});FAQ & Troubleshooting
Messages are not reaching phones. The default provider is log. Set TEXTIFY_PROVIDER to a real gateway and confirm its credentials are in .env.
How do I confirm credentials work? Run php artisan textify:test --driver=revesms --to=01712345678, or call Textify::via('revesms')->getBalance().
Queued messages never send. queue() dispatches a job, so a queue worker must be running (php artisan queue:work). Failed jobs raise TextifyJobFailed.
The notification channel cannot find a number. Define routeNotificationForTextify() on the notifiable, or send to an ad hoc number with Notification::route('textify', '01712345678').
Activity tracking is empty. It is off by default. Set TEXTIFY_ACTIVITY_TRACKING_ENABLED=true and, for the database driver, publish and run the migration with textify:table.
Changelog & Support
Release history is in the CHANGELOG and on the GitHub releases page. Open bugs and feature requests in GitHub issues. Source: DevWizardHQ/laravel-textify. For help wiring SMS into a larger product, the DevWizard team takes project contracts and monthly retainers through the contact page.