Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Smsmode Library Laravel Package

webeweb/smsmode-library

A lightweight PHP library for sending SMS through SMSMode, with a simple API for composing messages, managing recipients, and handling delivery responses. Integrates cleanly into Laravel or any PHP project via Composer, wrapping the SMSMode HTTP API so you can send single or bulk texts and check sta...

Deep Wiki
Context7

Getting Started

webeweb/smsmode-library is a framework-agnostic PHP SDK for the sMsmode REST API, not a Laravel package. There is no service provider, no facade, no publishable config. Plan on roughly fifteen minutes of wiring before your first message goes out.

Install and locate the moving parts

composer require webeweb/smsmode-library

Before writing a line of application code, open vendor/webeweb/smsmode-library/src and read three things: the top-level API class (typically Webeweb\Smsmode\API\SmsModeAPI or similar), the Request/ directory, and the Response/ directory. The webeweb family of libraries follows a consistent shape — an API object holding configuration, Request value objects you populate fluently, and Response objects with getters — so once you recognise the pattern in one class you can infer the rest. Also glance at vendor/webeweb/core-library, which supplies the HTTP transport and the RequestInterface/ResponseInterface contracts; that is where retries, timeouts, and error surfacing actually happen.

Credentials. sMsmode authenticates with an API key sent as a request header (X-Api-Key), plus a sender ID ("from") that must be pre-registered/validated on your sMsmode account. Put the key in config/services.php:

'smsmode' => [
    'api_key' => env('SMSMODE_API_KEY'),
    'from'    => env('SMSMODE_FROM', 'MyApp'),
],

First use case: a single transactional SMS (OTP on signup is the canonical one).

use Webeweb\Smsmode\API\SmsModeAPI;
use Webeweb\Smsmode\Request\SendSmsRequest;

$api = new SmsModeAPI(['api_key' => config('services.smsmode.api_key')]);

$request = (new SendSmsRequest())
    ->setFrom(config('services.smsmode.from'))
    ->setMessage('Votre code : 123456')
    ->setDestinataires(['+33612345678']);

$response = $api->sendSms($request);

Exact method names vary between minor versions and are not documented in this assessment — verify against the source before committing. Treat the snippet as a shape, not a contract.

Implementation Patterns

Bind the client as a singleton. Constructing the API object per call is cheap but scatters credentials through your codebase. One binding in AppServiceProvider:

$this->app->singleton(SmsModeAPI::class, fn () => new SmsModeAPI([
    'api_key' => config('services.smsmode.api_key'),
]));

Wrap it in a first-party service. Do not let SmsModeAPI leak into controllers, jobs, and notifications. Write App\Services\Sms\SmsSender with send(string $to, string $text): SmsResult and credit(): int. This is the single most valuable thing you can do with a 10-star dependency: it makes the vendor replaceable in an afternoon and makes the class mockable in tests.

Integrate with Laravel notifications. A notification channel is the natural fit, because it gives you via(), toMail-style per-channel payloads, and routeNotificationFor() for the phone number:

class SmsChannel
{
    public function __construct(private SmsSender $sms) {}

    public function send($notifiable, Notification $notification): void
    {
        if (! $to = $notifiable->routeNotificationFor('sms')) {
            return;
        }
        $this->sms->send($to, $notification->toSms($notifiable)->text);
    }
}

Then class OrderShipped extends Notification implements ShouldQueue — the queue handles the latency, and you get retries and backoff for free.

Queue bulk sends, never loop inline. A campaign to 5,000 recipients will blow past your request timeout and the API's rate limit. Dispatch a job per batch of ~100 with a RateLimited middleware job (Illuminate\Queue\Middleware\RateLimited) throttled to whatever your sMsmode plan permits. Use retryUntil rather than a fixed retry count for large batches.

Handle delivery asynchronously. A successful send only means the API accepted the message; it returns a message ID. Actual delivery arrives later, either via delivery-report polling or a webhook. Persist the message ID and status on your own sms_messages table at send time, then reconcile:

Route::post('/webhooks/smsmode', SmsModeWebhookController::class)
    ->withoutMiddleware(['csrf']);

Verify the payload (shared secret in the URL, IP allowlist, or signature header — check what your sMsmode account offers) and make the handler idempotent on message ID.

Testing. Because the library brings its own cURL-based transport, Http::fake() will not intercept it. Bind a fake SmsSender implementation in TestCase::setUp() and assert on an in-memory array of sent messages. For the one or two tests that exercise the real adapter, mark them @group integration and skip when SMSMODE_API_KEY is absent.

Gotchas and Tips

It is not a Laravel package, and it will never auto-discover. Expect no config file to publish and no facade. Everything above is manual wiring. Budget for it.

Accepted ≠ delivered. The most common bug in SMS integrations: setting status = 'delivered' on an HTTP 200. A 200 means "queued." Only a delivery report means delivered. Model the state machine explicitly (queued → sent → delivered | failed | expired).

Phone number hygiene is your job. Normalise to E.164 (+33612345678, no spaces, no 0 prefix for French numbers) before the call. sMsmode will reject malformed numbers, and the library's error surface may be a generic exception rather than a field-level message. Validate with a regex or propaganistas/laravel-phone upstream of your service class.

Segments cost money. GSM-7 vs UCS-2 encoding is decided by the content: a single accented character or emoji drops you to UCS-2 and halves the characters per segment (70 vs 160). A "short" message with a curly apostrophe can silently become two billed segments. Count segments in your own code and log it.

The from sender must be pre-approved. In France, alphanumeric sender IDs need to be registered with sMsmode and are subject to restrictions. A send that works in staging with one sender ID may fail in production with another. Keep from in config, never hardcoded.

Error handling is coarse. The webeweb style tends toward fluent setters and response objects with getters; failures may come back as an exception or as a response object with an error payload, depending on the call. Wrap every call in try/catch (\Throwable) and branch on both. Log the request (minus the API key) and the raw response body — the transport in core-library may not give you much detail otherwise.

Retries must be status-aware. Retry 429 and 5xx with exponential backoff. Never retry 4xx — an invalid number or rejected sender will fail identically forever, and retrying burns your rate limit. If you use Laravel's HTTP client somewhere else in the flow, do not assume its middleware applies here; the SDK has its own transport.

Version pinning matters more than usual. 10 stars, single maintainer, and a future-dated release (2026-09-11) suggest a low-traffic project. Pin with "webeweb/smsmode-library": "^1.0" and check the PHP constraint against your Laravel version (Laravel 11/12 want PHP 8.2+; older webeweb releases may cap at 8.1). Run composer why-not if it blocks an upgrade.

Extension points, if you need them. The core-library contracts (RequestInterface, ResponseInterface, and the HTTP adapter) are the intended seam. For anything non-trivial — custom headers, tracing, connection pooling — implement your own transport against those interfaces rather than forking. For everything simpler, wrap the API class rather than extending it; subclassing couples you to internal method signatures that may shift in a patch release.

Watch for STOP/opt-out lists. sMsmode maintains unsubscribe state per account. Don't build your own suppression list in parallel and assume it's authoritative — check with the provider's contact endpoints before bulk campaigns, or you will send to people who have already opted out.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource