unicodeveloper/jusibe-php-lib
A simple PHP library for the Jusibe SMS API, letting you send text messages, check your remaining SMS credits, and query delivery status from your Laravel or PHP applications, with straightforward methods and minimal setup for Nigerian SMS messaging.
This is a plain PHP client — not a Laravel package. There is no service provider, facade, or auto-discovery. Expect to spend the first 20 minutes wiring it yourself.
composer require unicodeveloper/jusibe-php-lib
Read the package README first for exact method signatures; the public surface is small and centers on sendSMS(), balance/credit checks, and delivery-status lookups on a Jusibe client constructed with (public_key, access_token).
Configure credentials in config/services.php (Laravel convention, not the package's):
// config/services.php
'jusibe' => [
'public_key' => env('JUSIBE_PUBLIC_KEY'),
'access_token' => env('JUSIBE_ACCESS_TOKEN'),
'from' => env('JUSIBE_SENDER_ID', 'MyApp'),
],
Wire it up yourself with a dedicated provider:
// app/Providers/JusibeServiceProvider.php
public function register(): void
{
$this->app->singleton(Jusibe::class, fn () => new Jusibe(
config('services.jusibe.public_key'),
config('services.jusibe.access_token'),
));
}
First use case: transactional SMS — OTPs, delivery confirmations, payment alerts. Start there, not with bulk marketing.
$response = app(Jusibe::class)->sendSMS(
to: $user->phone,
from: config('services.jusibe.from'),
message: 'Your verification code is 123456',
);
Inject, don't instantiate inline. Bind Jusibe as a singleton and type-hint it in controllers, jobs, and services. Never new Jusibe(...) in application code — it makes testing and credential rotation painful.
Wrap it in a SmsGateway interface. The library returns raw decoded arrays; you want your own send() contract returning a small DTO (message_id, status, units_used). This protects your app from method-name churn and lets you swap providers or add a second carrier without touching call sites.
A Laravel Notification channel is the cleanest integration point. Build a small JusibeChannel + toJusibe() method on notifiable classes. Then $user->notify(new OtpNotification($code)) and let framework plumbing handle the rest. This keeps SMS sends out of controllers.
Always queue. Wrap sends in a ShouldQueue job with $tries = 3 and $backoff = [10, 60, 300]. SMS is a network call to a Nigerian endpoint — you do not want it on the request/response path.
Treat delivery status as an eventual-consistency problem. Persist the message_id returned from sendSMS() and poll/reconcile later (or rely on Jusibe webhooks if enabled). Never assume "Sent" means "Delivered."
Add a balance health check. Register an Artisan command or scheduled task that calls the balance endpoint and alarms when credits drop below a threshold. Jusibe fails silently hard when you run out mid-campaign.
A lightweight Facade is optional. Add one only if you have many call sites; constructor injection is cleaner and easier to mock.
Observability hooks: log every request/response pair (redact the access token) with the recipient and message ID. When a customer says "I didn't get it," you need the correlation ID.
Maintenance risk is real. Last release was July 2020. Check compatibility with PHP 8.x and Guzzle 7 before committing — the package may pin an older Guzzle constraint that conflicts with a modern Laravel install. Test composer update in a throwaway branch first. If it breaks, either fork it (the code is tiny) or call the REST API directly with Http::withBasicAuth().
No Laravel service provider means no auto-discovery. If you skip the provider step, the class simply won't resolve from the container.
Sender ID must be pre-approved by Jusibe. Unregistered from values will fail silently or return an error in the body — not necessarily a non-2xx HTTP status.
Don't trust HTTP status alone. Jusibe often returns 200 OK with an error/status: "Failed" field in the JSON body. Parse the payload and treat status, error, and absence of message_id as failure signals. Wrap all calls in a try/catch and inspect the response.
Multipart messages cost more. Any message over ~160 characters (and depending on encoding, less) bills as multiple sms_units_used. Cap message length in a FormRequest or value object, and surface sms_units_used in your logs so cost surprises are visible.
Credentials are HTTP Basic Auth. Never hardcode them; keep them in .env. Rotate immediately if a key leaks — every request carries the token.
Rate limits and retries. Implement exponential backoff on 429/5xx responses. Retrying a timeout on sendSMS risks duplicate messages — de-duplicate with an idempotency key or a short-lived cache lock on (recipient + message hash).
Testing. Mock the SmsGateway interface in unit tests. For integration-style tests, stub the underlying Guzzle handler (or Http::fake() if you bypass the library) rather than hitting Jusibe. Assert on your DTO mappings, not the library's internals.
Extension point. If you need features the library lacks (bulk, templates, webhooks), fork it — it's a thin wrapper, so maintaining your own fork inside app/Support/ is often cheaper than fighting upstream.
How can I help you explore Laravel packages today?