SDKs
PHP SDK
Install the PHP SDK, send a message, handle errors, and know what it checks before it sends.
mycomm/mycomm-php is the official client for PHP 8.2+. It has a method for every operation of the API, typed arguments and
results, retries that cannot double-send, a check of your arguments before a request goes out, and webhook verification.
composer require mycomm/mycomm-php
composer require guzzlehttp/guzzle # any PSR-18 HTTP client works; Guzzle is used if installed
Send a message#
use MyComm\Client;
$mycomm = new Client(getenv('MYCOMM_API_KEY'));
$message = $mycomm->messages->send(
to: '+923001234567',
body: 'Your order #1094 is ready for pickup.',
category: 'transactional',
reference_id: 'order-1094',
);
echo $message->id;
echo $message->status->value; // "queued" (MessageStatus::Queued)
Every resource of the API reference is a property of the client (messages, contacts, webhookEndpoints, ...) and
every operation a method on it. Arguments are named like the API's fields, so the reference and your editor agree; pass them by name.
What it checks before sending#
The limits and rules of the OpenAPI document are checked first, and a mistake fails at once with the field named:
use MyComm\Exceptions\InvalidArgumentException;
try {
$mycomm->messages->send(to: $number, body: $text, expires_in: 30);
} catch (InvalidArgumentException $e) {
echo $e->getMessage(); // expires_in must be between 60 and 604800 (got 30).
$e->field; // "expires_in"
$e->rule; // "OUT_OF_RANGE"
$e->violations; // every problem found, not only the first
}
It checks ranges and lengths, allowed values, UUID format, metadata size and types, that you give exactly one of to and
contact_id and at least one content field, that variables comes with template_id, and that category comes with the bulk
lane. The list is generated from the contract, so it follows the API. What depends on state, such as an opt-out, is answered by the
server. If the API relaxes a rule before you update the SDK, create the client with validate: false.
Handle errors#
Every error answer is an exception with the code, status, message, details and request id.
use MyComm\Enums\ErrorCode;
use MyComm\Exceptions\ApiException;
try {
$mycomm->messages->send(to: $number, body: $text, category: 'marketing');
} catch (ApiException $e) {
if ($e->is(ErrorCode::RecipientOptedOut)) {
// do not retry: the recipient unsubscribed
}
logger()->warning($e->summary()); // RECIPIENT_OPTED_OUT (422): The recipient ... details: {...} request_id: ...
$e->docUrl(); // the error reference entry for this code
}
$e->code() is the enum case, or null for a code newer than your SDK; $e->errorCode is the same value as text. A validation
error lists its fields: ValidationException::fields() and summary(). The exception types by status are in the package
README. getMessage() says what happened and what to do; never parse it.
Retries and idempotency#
The SDK retries twice (configurable) after a network error, a 429, a 503 or another 5xx, waiting as long as Retry-After asks
(a number of seconds or an HTTP date). Every POST carries an Idempotency-Key, and a retry repeats the same key, so a retried
send cannot send twice. Pass your own to make a whole job repeatable:
use MyComm\RequestOptions;
$mycomm->messages->send(
to: $order->phone,
body: "Order {$order->number} has shipped.",
requestOptions: new RequestOptions(idempotencyKey: "order-shipped-{$order->id}", maxRetries: 0),
);
The rules behind this are on Idempotency and retries.
Verify your settings#
$result = $mycomm->verify(to: '+923001234567', lineId: 'LINE_ID'); // lineId may be left out with a key limited to one line
if (! $result->ok()) {
foreach ($result->problems() as $problem) {
echo $problem, "\n";
}
}
verify() checks the key and dry-runs a send to your number. It sends nothing, and it reports a failure as a failed check, not an
exception. See Verify your integration.
Webhooks#
use MyComm\Webhooks\Webhook;
use MyComm\Webhooks\Events\MessageDelivered;
$event = Webhook::constructEvent($rawBody, $_SERVER['HTTP_MYCOMM_SIGNATURE'], $secret); // throws if the signature is wrong
if ($event instanceof MessageDelivered) {
$event->data->message->id;
}
There is a class for each event in the event catalogue; a type newer than the SDK arrives as UnknownEvent. Verification
accepts a rotated secret during the overlap and rejects a timestamp more than 300 seconds off.
Test your own code#
MyComm\Testing\MyCommFake replaces the network: every operation answers with the example of the reference unless you stub it.
$fake = new MyCommFake;
$fake->respond('messages.send', FakeResponse::error(422, 'RECIPIENT_OPTED_OUT'));
$service = new NotifyCustomer($fake->client());
// ... then $fake->assertCalled('messages.send');
The package README has the full reference, the partner API ($mycomm->partner->accounts->provision(...)) and the changelog.