gennet/sms

Framework-independent PHP SDK for the Gennet SMS API

Maintainers

Package info

github.com/engrmukul/gennet-sms-php

pkg:composer/gennet/sms

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-08-24 12:30 UTC

This package is auto-updated.

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


README

A framework-independent PHP SDK for the Gennet SMS API. No Laravel dependency — a Laravel-specific SDK will be built separately on top of this core package.

Requirements

  • PHP >= 8.1
  • guzzlehttp/guzzle ^7.8

Installation

composer require gennet/sms

Usage

use Gennet\Sms\GennetClient;

$gennet = new GennetClient(
    apiToken: getenv('GENNET_API_TOKEN')
);

$response = $gennet->messages()->send(
    sid: 'GENNET',
    msisdn: '8801712345678',
    message: 'Hello from Gennet',
    csmsId: 'ORDER1001'
);

print_r($response->data());

Bulk SMS

$response = $gennet->messages()->sendBulk(
    sid: 'GENNET',
    msisdn: ['8801712345678', '8801812345678'],
    message: 'Bulk message',
    batchCsmsId: 'BATCH1001'
);

Dynamic SMS

use Gennet\Sms\ValueObjects\DynamicMessage;

$response = $gennet->messages()->sendDynamic(
    sid: 'GENNET',
    messages: [
        new DynamicMessage(msisdn: '8801712345678', text: 'Hello A', csmsId: 'MSG1001'),
        new DynamicMessage(msisdn: '8801812345678', text: 'Hello B', csmsId: 'MSG1002'),
    ],
);

Status, balance, transfer, and incoming SMS

$gennet->messages()->status(csmsId: 'ORDER1001');
$gennet->balance()->get();
$gennet->balance()->transfer(sid: 'GENNET', toSid: 'OTHER_SID', amount: 100.0);
$gennet->incoming()->list();

Configuration

$gennet = new GennetClient(
    apiToken: getenv('GENNET_API_TOKEN'),
    baseUrl: 'https://isms.gennet.com.bd',
    timeout: 15.0,
    connectTimeout: 5.0,
    endpoints: [
        'send' => '/api/v3/sms-send',
        // Only /api/v3/sms-send is confirmed against production today.
        // Override the rest here once your account's routes are confirmed.
        'bulk' => '/api/v3/sms-send-bulk',
        'dynamic' => '/api/v3/sms-send-dynamic',
        'status' => '/api/v3/sms-status',
        'balance' => '/api/v3/balance',
        'transfer' => '/api/v3/balance-transfer',
        'incoming' => '/api/v3/incoming',
    ],
);

Note: Only POST /api/v3/sms-send is confirmed against the production API at this time. The other endpoint paths above are placeholders — pass your account's real values via the endpoints option once confirmed. See "API routes requiring confirmation" below.

Authentication

The SDK sends the configured API token via the X-API-TOKEN header by default:

X-API-TOKEN: <token>

The token is never logged, and it is redacted from any exception message before the exception is thrown. Query-parameter authentication is not used.

Error handling

The Gennet SMS API can return HTTP 200 with an internal failure payload, e.g.:

{
  "status": "FAILED",
  "status_code": 4029,
  "status_meaning": "Too many requests",
  "description": "..."
}

The SDK inspects the JSON body on every response — not just the HTTP status code — and converts internal failures into typed exceptions:

  • Gennet\Sms\Exceptions\GennetException — base class for all SDK exceptions.
  • ApiException — generic API-level failure.
  • AuthenticationException — invalid/expired token.
  • ValidationException — invalid parameters caught locally, before any HTTP call.
  • RateLimitException — thrown for status_code: 4029 ("Too many requests").
  • InsufficientBalanceException — thrown when the account balance is too low.
  • TransportException — network/connection failures (DNS, timeout, etc.).
  • ServerException — HTTP 5xx or unparsable responses.
use Gennet\Sms\Exceptions\RateLimitException;
use Gennet\Sms\Exceptions\GennetException;

try {
    $gennet->messages()->send(sid: 'GENNET', msisdn: '8801712345678', message: 'Hi', csmsId: 'ORDER1001');
} catch (RateLimitException $e) {
    // back off and retry later, at the caller's discretion
} catch (GennetException $e) {
    // any other SDK error
}

Retry policy

The SDK never automatically retries SMS-sending requests (send, sendBulk, sendDynamic, transfer), because the API does not yet guarantee idempotency for these calls. Automatic retries are only safe to consider for read-only requests such as status, balance()->get(), and incoming()->list(), and even then the SDK leaves that decision to the caller.

Testing

The SDK is fully testable without calling production by injecting a Guzzle client backed by GuzzleHttp\Handler\MockHandler:

use Gennet\Sms\GennetClient;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;

$mock = new MockHandler([
    new Response(200, [], json_encode(['status' => 'SUCCESS'])),
]);
$guzzle = new Client(['handler' => HandlerStack::create($mock)]);

$gennet = new GennetClient(apiToken: 'test-token', httpClient: $guzzle);

Run the test suite:

composer install
vendor/bin/phpunit

API routes still requiring confirmation

Only POST /api/v3/sms-send has been confirmed against the production API. The following endpoint paths are placeholders and must be confirmed (and overridden via the endpoints constructor option if different) before production use:

  • Bulk SMS
  • Dynamic SMS
  • SMS delivery/status lookup
  • SMS balance check
  • SMS balance transfer
  • Incoming SMS list

License

MIT