sashalenz / turbosms-notification-channel
Laravel notification channel for the TurboSMS REST API
Package info
github.com/sashalenz/turbosms-notification-channel
pkg:composer/sashalenz/turbosms-notification-channel
Requires
- php: ^8.2
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/http: ^11.0|^12.0|^13.0
- illuminate/notifications: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^2.9|^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-arch: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
- phpstan/extension-installer: ^1.3
README
A Laravel notification channel for the TurboSMS REST API.
This is a drop-in replacement for the abandoned
laravel-notification-channels/turbosms
package, which still talks to the long-deprecated SOAP endpoint and fails on
modern PHP with SoapClient::__construct(): 'location' and 'uri' options are required in nonWSDL mode.
Why this package
- Talks to the current TurboSMS REST API (
https://api.turbosms.ua), not the dead SOAP endpoint. - Won't crash your queue. Auth, transport, and per-recipient errors are
logged at
warninglevel instead of being thrown — so a flaky provider or a missing API key cannot drown your worker in retries. - Sandbox mode that short-circuits before any HTTP call — useful for local dev where you don't want to spend credits.
- Auto-normalises phones —
+380501234567,380501234567,+38 (050) 123-45-67all become380501234567before hitting the API.
Installation
composer require sashalenz/turbosms-notification-channel
The service provider is registered automatically via package discovery.
Publish the config (optional — env-driven defaults work out of the box):
php artisan vendor:publish --tag="turbosms-config"
Configuration
Set the following keys in your .env:
TURBOSMS_API_KEY=your-bearer-token-from-the-dashboard TURBOSMS_SENDER=YourAlpha # Optional TURBOSMS_SANDBOX_MODE=false TURBOSMS_DEBUG=false TURBOSMS_BASE_URL=https://api.turbosms.ua TURBOSMS_TIMEOUT=10
The Bearer token is issued in the TurboSMS dashboard.
Usage
1. Notification
Add the channel to your notification's via() and implement toTurboSms:
use Illuminate\Notifications\Notification; use Sashalenz\TurboSms\TurboSmsChannel; use Sashalenz\TurboSms\TurboSmsMessage; class OrderShipped extends Notification { public function via(object $notifiable): array { return [TurboSmsChannel::class]; } public function toTurboSms(object $notifiable): TurboSmsMessage { return new TurboSmsMessage("Your order #{$notifiable->id} has shipped."); } }
Method names in PHP are case-insensitive, so legacy notifications declaring
toTurboSMSwill keep working without modification.
2. Notifiable
Provide the recipient phone via routeNotificationForTurbosms (or the
case-insensitive equivalent routeNotificationForTurboSMS). Any common
format works — the channel strips non-digit characters before sending:
class User extends Authenticatable { use Notifiable; public function routeNotificationForTurbosms(): string { return $this->phone; // '+380501234567' → '380501234567' on the wire } }
3. Send
$user->notify(new OrderShipped($order));
Sandbox mode
Set TURBOSMS_SANDBOX_MODE=true to short-circuit every send. No HTTP request
is made; if TURBOSMS_DEBUG=true the would-be payload is logged at info
level. Useful in local/staging environments.
Failure semantics
The channel is intentionally non-throwing — every failure path logs a warning and returns:
| Scenario | Result | Log level |
|---|---|---|
sandbox_mode = true |
no-op | info (only if debug = true) |
Empty api_key or sender |
no-op | warning |
| Empty recipient phone or message body | no-op | none |
| Transport error (timeout, DNS, refused) | no-op | warning |
| HTTP 401 / 403 | no-op | warning |
| Other non-2xx | no-op | warning |
Envelope response_code != 0 (e.g. insufficient funds) |
no-op | warning |
Per-recipient response_code != 0 (e.g. invalid phone) |
no-op | warning |
| Successful send | sent | info (only if debug = true) |
This matches the design constraint that a misconfigured SMS provider should not block delivery, fiscalisation, or any other queued workflow that happens to dispatch an SMS as a side-effect.
Testing
composer test
Tests use Http::fake() and Orchestra Testbench — no real HTTP calls are
made.
License
MIT — see LICENSE.