gennet / sms
Framework-independent PHP SDK for the Gennet SMS API
Requires
- php: >=8.1
- guzzlehttp/guzzle: ^7.8
Requires (Dev)
- phpunit/phpunit: ^10.5 || ^11.0
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-sendis confirmed against the production API at this time. The other endpoint paths above are placeholders — pass your account's real values via theendpointsoption 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 forstatus_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