Guide
Gateways and testing
The http driver
Almost every regional SMS gateway is the same thing: a URL, a few parameters with names of its own choosing, and a response you have to squint at. So it is configuration rather than code.
'gateways' => [
'mygateway' => [
'driver' => 'http',
'url' => 'https://api.example.com/send',
'method' => 'POST', // or GET
'json' => false, // send the body as JSON rather than a form
'headers' => ['Authorization' => 'Bearer '.env('SMS_TOKEN')],
'params' => [
'to' => ':to',
'body' => ':text',
'sender' => ':from',
'encoding' => ':encoding',
],
'text_value' => 'GSM',
'unicode_value' => 'UCS2',
'success' => ['json' => ['status' => 'ok']],
'id_path' => 'data.messageId',
'error_path' => 'error.message',
'timeout' => 15,
],
],
| In a value | Becomes |
|---|---|
:to |
+923001234567 |
:to_plain |
923001234567 |
:text |
the message |
:from |
the sender ID |
:parts |
how many parts it will be billed as |
:encoding |
text_value or unicode_value |
:encoding matters more than it looks. Most gateways need to be told the
message is Unicode; send Arabic without the flag and the recipient gets question
marks, and you are still billed.
Recognising success
'success' => ['contains' => 'OK'], // the body has this in it
'success' => ['json' => ['status' => 'success']], // a field equals this
'success' => ['json' => ['data.code' => 0]], // nested, dotted
With no success rule, any 2xx is taken as sent.
Inside Laravel
The provider hands the http driver Laravel's own HTTP client, so Http::fake(),
retries, timeouts and request logging all work exactly as they do everywhere
else:
Http::fake(['api.example.com/*' => Http::response(['status' => 'ok'], 200)]);
$sender->send('0501234567', 'Hello');
Http::assertSent(fn ($request) => $request['to'] === '+971501234567');
Testing without a gateway
use Devix\Sms\Driver;
use Devix\Sms\Drivers\ArrayDriver;
$driver = new ArrayDriver;
$this->app->instance(Driver::class, $driver);
$user->notify(new VerificationCode('1234'));
$this->assertSame(1, $driver->count());
$this->assertSame('+971501234567', $driver->last()->to);
$this->assertStringContainsString('1234', $driver->last()->text);
// And the thing worth asserting that nobody asserts:
$this->assertSame(1, $driver->last()->cost()->parts, 'this notification must stay one message');
That last line is the one to copy. A template that grows by a sentence and silently becomes two parts is a doubled bill on every send, and it is exactly the kind of change that passes review.
A word about the gateways themselves
We have not run this against a live Jazz, Zong, Ufone, Telenor, Unifonic or Etisalat account. We do not have accounts with them, and a package that claimed tested support for a gateway nobody here has ever authenticated against would be dishonest.
What that means in practice:
- The http driver is declarative, so you can read exactly what it will send and check it against your operator's documentation without reading PHP.
- The
arraydriver lets you assert that request in your own test suite. - The
logdriver lets you watch it in development before you spend anything. - Everything before the request — the counting, the encoding flag, the E.164 number, the sender ID — is ours, and all of it is tested.
If you are on Twilio, use the official channel. It is maintained, it takes 303,601 downloads a month, and there is no reason to replace it. Use this for what happens before the send.