gennet/laravel-sms

Official standalone Laravel SDK for the Gennet SMS API

Maintainers

Package info

github.com/engrmukul/gennet-laravel-sms

pkg:composer/gennet/laravel-sms

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-24 19:32 UTC

This package is auto-updated.

Last update: 2026-08-24 19:34:17 UTC


README

Official standalone Laravel SDK for the Gennet SMS API.

This package talks to the Gennet SMS API directly over HTTP (Guzzle). It does not depend on the generic gennet/sms PHP SDK — it is self-contained and installs on its own into any Laravel 11/12/13 application.

Requirements

  • PHP >= 8.1
  • Laravel 11, 12 or 13

Installation

composer require gennet/laravel-sms

The service provider and GennetSms facade are auto-discovered.

Publish the config file:

php artisan vendor:publish --tag=gennet-sms-config

Configuration

Add to your .env:

GENNET_SMS_API_TOKEN=
GENNET_SMS_SENDER_ID=GENNET
GENNET_SMS_BASE_URL=https://isms.gennet.com.bd
GENNET_SMS_TIMEOUT=15
GENNET_SMS_CONNECT_TIMEOUT=5

Endpoint paths are also configurable and default to the verified Gennet SMS API v3 routes:

GENNET_SMS_ENDPOINT_SEND=/api/v3/send-sms
GENNET_SMS_ENDPOINT_BULK=/api/v3/send-sms/bulk
GENNET_SMS_ENDPOINT_DYNAMIC=/api/v3/send-sms/dynamic
GENNET_SMS_ENDPOINT_STATUS=/api/v3/send-sms/status
GENNET_SMS_ENDPOINT_BALANCE=/api/v3/balance
GENNET_SMS_ENDPOINT_TRANSFER=/api/v3/transfer-balance
GENNET_SMS_ENDPOINT_INCOMING=/api/v3/incoming-messages-list

Never commit real tokens or credentials to source control.

Usage

Single SMS

use Gennet\LaravelSms\Facades\GennetSms;

$response = GennetSms::send(
    msisdn: '8801712345678',
    message: 'Hello from Laravel'
);

A secure 20-character alphanumeric csms_id is generated automatically when omitted. You may provide your own, or override the configured sender ID per call:

$response = GennetSms::send(
    msisdn: '8801712345678',
    message: 'Your OTP is 123456',
    csmsId: 'OTP123456'
);

$response = GennetSms::send(
    msisdn: '8801712345678',
    message: 'Hello',
    csmsId: 'ORDER1001',
    sid: 'GENNET'
);

Bulk SMS

GennetSms::bulk(
    msisdns: ['8801712345678', '8801812345678'],
    message: 'Hello everyone',
    batchCsmsId: 'BATCH1001'
);

Dynamic (personalized) SMS

GennetSms::dynamic([
    ['msisdn' => '8801712345678', 'message' => 'Hello Karim', 'csms_id' => 'MSG1001'],
    ['msisdn' => '8801812345678', 'message' => 'Hello Rahim', 'csms_id' => 'MSG1002'],
]);

The Laravel-friendly message key is mapped internally to the API's text field.

Delivery status (DLR)

GennetSms::status(referenceId: '...');

Balance

$response = GennetSms::balance();

Balance transfer

GennetSms::transferBalance(
    fromSid: 'SID1',
    toSid: 'SID2',
    amount: 1000,
    remarks: 'Transfer to child account'
);

Incoming messages

GennetSms::incoming();

The production backend currently only requires/validates api_token for this endpoint. Additional array keys passed to incoming() are forwarded as extra query parameters for forward compatibility, but are not guaranteed to be understood by the API.

Dependency injection

use Gennet\LaravelSms\Contracts\GennetSmsContract;

class SmsService
{
    public function __construct(
        private GennetSmsContract $sms
    ) {}

    public function send(): void
    {
        $this->sms->send('8801712345678', 'Hello');
    }
}

Laravel Notification channel

use Gennet\LaravelSms\Notifications\GennetSmsChannel;
use Gennet\LaravelSms\Notifications\GennetSmsMessage;

class OtpNotification extends \Illuminate\Notifications\Notification
{
    public function via(object $notifiable): array
    {
        return [GennetSmsChannel::class];
    }

    public function toGennetSms(object $notifiable): GennetSmsMessage
    {
        return new GennetSmsMessage('Your OTP is 123456');
    }
}
class User extends Authenticatable
{
    public function routeNotificationForGennetSms(): string
    {
        return $this->phone;
    }
}

GennetSmsMessage also supports ->from('SENDERID') and ->clientReference('CSMS1001').

Exception handling

HTTP 200 does not always mean success — the Gennet API can return status: "FAILED" with a status_code inside a 200 response. This SDK detects that and throws a typed exception instead:

use Gennet\LaravelSms\Exceptions\ApiException;
use Gennet\LaravelSms\Exceptions\RateLimitException;
use Gennet\LaravelSms\Exceptions\InsufficientBalanceException;
use Gennet\LaravelSms\Exceptions\AuthenticationException;
use Gennet\LaravelSms\Exceptions\TransportException;

try {
    GennetSms::send(msisdn: '8801712345678', message: 'Hello');
} catch (RateLimitException $e) {
    // status_code 4029 — retry later
} catch (InsufficientBalanceException $e) {
    // status_code 4008
} catch (AuthenticationException $e) {
    // status_code 4001 — invalid API token
} catch (TransportException $e) {
    // network/DNS/timeout failure — no response was received
} catch (ApiException $e) {
    // any other API-level failure
    $e->apiStatusCode();
    $e->payload();
}

The full exception hierarchy: GennetSmsExceptionApiExceptionAuthenticationException, ValidationException, RateLimitException, InsufficientBalanceException, ServerException. TransportException is thrown directly from GennetSmsException for connection-level failures.

No automatic retries. send, bulk, dynamic and transferBalance are never retried automatically by this SDK, because retrying could cause duplicate SMS deliveries or duplicate balance transfers. Retry only if your application logic explicitly decides to.

Verified API routes

All endpoint defaults in this package were verified directly against the production Gennet SMS API v3 route definitions and controller/request classes — none were guessed:

Operation Method Path
Single SMS POST /api/v3/send-sms
Bulk SMS POST /api/v3/send-sms/bulk
Dynamic SMS POST /api/v3/send-sms/dynamic
Status (DLR) GET /api/v3/send-sms/status
Balance GET /api/v3/balance
Transfer balance POST /api/v3/transfer-balance
Incoming messages GET /api/v3/incoming-messages-list

Security

  • API tokens are sent via the X-API-TOKEN header and as api_token in the request body/query (matching the backend's accepted contract) — never logged.
  • Exception messages and payloads never include the API token.
  • No automatic retries on send/bulk/dynamic/transfer operations.
  • HTTPS is the default transport (https://isms.gennet.com.bd).

Testing

composer install
composer test

Tests use Orchestra Testbench and a Guzzle MockHandler — no real API calls are made.

License

MIT