nexiom/connect-php is the official SDK for PHP. It works in Laravel, Symfony, WordPress, or plain PHP, and retries safely for you.

Install

PHP 8.2 or later is required. The SDK uses Guzzle 7.9 or 8.

Terminal
composer require nexiom/connect-php

Initialize the client

Create one client on your server and reuse it. Load the API key from your environment; never ship it to the browser.

PHP
<?php

use Nexiom\Connect\NexiomConnect;

$apiKey = getenv('NEXIOM_API_KEY');
if (!$apiKey) {
    throw new RuntimeException('NEXIOM_API_KEY is required');
}

$nexiom = new NexiomConnect($apiKey);
apiKeyrequiredstring

Your API key, starting with nc_.

timeoutoptionalint or float

Total deadline per call in seconds, including retries. Default 30.

maxRetriesoptionalint

Extra attempts for reads, sends, and cancels. Default 2.

baseUrloptionalstring

API root. Default https://api-connect.nxiom.com/api.

httpClientoptionalGuzzleHttp\ClientInterface

A Guzzle client, for proxies, instrumentation, or tests.

Pass options by name, for example new NexiomConnect(apiKey: $apiKey, timeout: 10).

Send an email

Parameters are arrays with camelCase keys. Methods return the response data as an array.

PHP
<?php

$email = $nexiom->emails->send(
    [
        'from' => 'hello@mail.example.com',
        'fromName' => 'Acme',
        'to' => 'reader@example.com',
        'subject' => 'Your receipt',
        'html' => '<p>Thanks for your order.</p>',
        'text' => 'Thanks for your order.',
    ],
    ['idempotencyKey' => 'receipt-' . $order->id],
);

echo $email['messageId'];

Pass an idempotencyKey that identifies the email in your system. If you omit it, the SDK generates one per call, which protects its own retries but not a retry of your whole operation. See Sending email.

To send a template, pass templateId and templateVariables instead of subject and content.

Schedule an email

Pass scheduledAt as a DateTimeInterface or an ISO 8601 timestamp with an offset, up to 30 days ahead. Keep the returned messageId to move or cancel the send before it goes out.

PHP
<?php

$email = $nexiom->emails->send([
    'from' => 'hello@mail.example.com',
    'to' => 'reader@example.com',
    'subject' => 'Your trial ends soon',
    'text' => 'Your trial ends soon.',
    'scheduledAt' => new DateTimeImmutable('+1 day'),
]);

// Move it one day later, or cancel it before it is sent.
$nexiom->emails->reschedule($email['messageId'], [
    'scheduledAt' => new DateTimeImmutable('+2 days'),
]);
$nexiom->emails->cancel($email['messageId']);

See Reschedule and Cancel for the rules.

Read email logs

emails->list and emails->get need a full-access key. list pages with a cursor; get takes a delivery ID, not a message ID.

PHP
<?php

$page = $nexiom->emails->list(['status' => 'bounced', 'limit' => 50]);

$first = $page['items'][0] ?? null;

if ($first !== null) {
    $delivery = $nexiom->emails->get($first['id']);

    echo $delivery['recipient'], ' ', $delivery['delivery_reason'];
}

// nextCursor is null on the last page.
if ($page['nextCursor'] !== null) {
    $nexiom->emails->list(['status' => 'bounced', 'cursor' => $page['nextCursor']]);
}

See List emails and Retrieve an email for every field.

Manage contacts

Define a contact property before you store a value for it.

PHP
<?php

$nexiom->contacts->properties->create(['name' => 'plan', 'type' => 'string']);

$contact = $nexiom->contacts->create([
    'email' => 'reader@example.com',
    'firstName' => 'Sam',
    'properties' => ['plan' => 'pro'],
]);

$nexiom->contacts->update($contact['id'], [
    'email' => 'reader@example.com',
    'emailStatus' => 'unsubscribed',
]);

$page = $nexiom->contacts->list(['search' => 'example.com', 'limit' => 50]);

contacts->get, contacts->delete, and contacts->properties are available too. Responses use snake_case fields such as first_name. See the Contacts API for every field.

Send a WhatsApp message

messaging->send sends on every messaging channel; channel selects the parameters. For WhatsApp, send an approved template from your connected number, named by its phone number in from. Requires 0.4.0 or later and a key with the whatsapp.send permission.

PHP
$message = $nexiom->messaging->send(
    [
        'channel' => 'whatsapp',
        'from' => '+213555000111',
        'to' => '+213555123456',
        'template' => [
            'id' => 'wat_example',
            'variables' => ['body' => [1 => 'Amina', 2 => 'A-1234']],
        ],
    ],
    ['idempotencyKey' => 'order-A-1234-shipped'],
);

$current = $nexiom->messaging->get($message['id']);

echo $current['status'];

See Sending WhatsApp messages.

Verify webhooks

webhooks->constructEvent (0.4.0 or later) checks a webhook request's signature and timestamp, and returns the event as an array. Pass the raw body, not decoded JSON. In a Laravel controller or route:

PHP
$event = $nexiom->webhooks->constructEvent(
    $request->getContent(),
    $request->headers->all(),
    config('services.nexiom.webhook_secret'),
);

if ($event['type'] === 'email.bounced') {
    error_log($event['data']['recipient']);
}

It throws NexiomWebhookVerificationException when the request is not genuine. Outside Laravel, pass file_get_contents('php://input') and getallheaders(). See Verify webhook requests for a complete Laravel route.

Handle errors

API and transport failures throw Nexiom\Connect\Exceptions\NexiomException.

PHP
<?php

use Nexiom\Connect\Exceptions\ErrorKind;
use Nexiom\Connect\Exceptions\NexiomException;

try {
    $email = $nexiom->emails->send($message, ['idempotencyKey' => $idempotencyKey]);
} catch (NexiomException $error) {
    if ($error->kind === ErrorKind::Api && $error->status === 429) {
        // Rate limited: try again later with the same idempotency key.
    }

    error_log("{$error->status} {$error->errorCode} {$error->getMessage()} {$error->requestId}");
    throw $error;
}
PropertyDescription
kindErrorKind::Api for an error response; otherwise Network, Timeout, or Protocol.
statusHTTP status, when the API responded.
errorCodeMachine-readable error code, when present.
requestIdThe request's correlation ID. Include it when contacting support.
detailsAdditional error details, such as validation failures.

Invalid arguments — for example a missing from, or an unknown key such as from_name — throw a NexiomValidationException before any request is made.

Retries and timeouts

The SDK retries reads, sends and cancels on 408, 429, and 5xx responses and on network failures, honouring Retry-After. Sends are retried with the same idempotency key, so a retry never sends twice. Other writes, such as creating a contact or rescheduling an email, are not retried automatically. If Retry-After asks for a longer wait than the remaining timeout, the SDK throws that error straight away.

Override per call by passing ['timeout' => ..., 'maxRetries' => ...] as the method's last argument.

Nexiom Connect
Open dashboard