PHP SDK

PHP SDK

The official PHP SDK for Sent LogoSent provides a clean, object-oriented interface for sending messages. Built with modern PHP 8.1+ features.

Requirements

PHP 8.1.0 or higher.

Installation

composer require sentdm/sent-dm-php

To install a specific version:

composer require "sentdm/sent-dm-php 0.6.0"

Quick Start

Initialize the client

<?php
require_once 'vendor/autoload.php';

use SentDM\Client;

$client = new Client($_ENV['SENT_DM_API_KEY']);  // Your API key from the Sent Dashboard

Send your first message

<?php
require_once 'vendor/autoload.php';

use SentDM\Client;

$client = new Client($_ENV['SENT_DM_API_KEY']);

$result = $client->messages->send(
    to: ['+1234567890'],
    template: [
        'id' => '7ba7b820-9dad-11d1-80b4-00c04fd430c8',
        'name' => 'welcome',
        'parameters' => [
            'name' => 'John Doe',
            'order_id' => '12345'
        ]
    ],
    channels: ['sms', 'whatsapp'] // Optional
);

var_dump($result->data->messages[0]->id);
var_dump($result->data->messages[0]->status);

Authentication

The client accepts an API key as the first parameter.

use SentDM\Client;

// Using API key directly
$client = new Client('your_api_key');

// Or from environment variable
$client = new Client($_ENV['SENT_DM_API_KEY']);

Send Messages

This library uses named parameters to specify optional arguments. Parameters with a default value must be set by name.

Send a message

$result = $client->messages->send(
    to: ['+1234567890'],
    template: [
        'id' => '7ba7b820-9dad-11d1-80b4-00c04fd430c8',
        'name' => 'welcome',
        'parameters' => [
            'name' => 'John Doe',
            'order_id' => '12345'
        ]
    ],
    channels: ['sms', 'whatsapp']
);

var_dump($result->data->messages[0]->id);
var_dump($result->data->messages[0]->status);

Test mode

Use testMode: true to validate requests without sending real messages:

$result = $client->messages->send(
    to: ['+1234567890'],
    template: [
        'id' => '7ba7b820-9dad-11d1-80b4-00c04fd430c8',
        'name' => 'welcome'
    ],
    testMode: true // Validates but doesn't send
);

// Response will have test data
var_dump($result->data->messages[0]->id);
var_dump($result->data->messages[0]->status);

Handling errors

When the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of SentDM\Core\Exceptions\APIException will be thrown:

use SentDM\Core\Exceptions\APIConnectionException;
use SentDM\Core\Exceptions\RateLimitException;
use SentDM\Core\Exceptions\APIStatusException;

try {
    $result = $client->messages->send(
        to: ['+1234567890'],
        template: [
            'id' => '7ba7b820-9dad-11d1-80b4-00c04fd430c8',
            'name' => 'welcome'
        ]
    );
} catch (APIConnectionException $e) {
    echo "The server could not be reached", PHP_EOL;
    var_dump($e->getPrevious());
} catch (RateLimitException $e) {
    echo "A 429 status code was received; we should back off a bit.", PHP_EOL;
} catch (APIStatusException $e) {
    echo "Another non-200-range status code was received", PHP_EOL;
    echo $e->getMessage();
}

Error codes are as follows:

CauseError Type
HTTP 400BadRequestException
HTTP 401AuthenticationException
HTTP 403PermissionDeniedException
HTTP 404NotFoundException
HTTP 409ConflictException
HTTP 422UnprocessableEntityException
HTTP 429RateLimitException
HTTP >= 500InternalServerException
Other HTTP errorAPIStatusException
TimeoutAPITimeoutException
Network errorAPIConnectionException

Retries

Certain errors will be automatically retried 2 times by default, with a short exponential backoff.

// Configure the default for all requests:
$client = new Client($_ENV['SENT_DM_API_KEY'], maxRetries: 0);

// Or, configure per-request:
$result = $client->messages->send(
    to: ['+1234567890'],
    template: [
        'id' => '7ba7b820-9dad-11d1-80b4-00c04fd430c8',
        'name' => 'welcome'
    ],
    requestOptions: ['maxRetries' => 5],
);

Value Objects

It is recommended to use the static with constructor and named parameters to initialize value objects.

use SentDM\Models\TemplateDefinition;

$definition = TemplateDefinition::with(
    body: [...],
    header: [...],
);

However, builders are also provided:

$definition = (new TemplateDefinition)->withBody([...]);

Contacts

Create and manage contacts:

// Create a contact
$result = $client->contacts->create([
    'phoneNumber' => '+1234567890'
]);

var_dump($result->data->id);

// List contacts
$result = $client->contacts->list(['limit' => 100]);

foreach ($result->data->data as $contact) {
    echo $contact->phoneNumber . " - " . implode(', ', $contact->availableChannels) . "\n";
}

// Get a contact
$result = $client->contacts->get('contact-uuid');

// Update a contact
$result = $client->contacts->update('contact-uuid', [
    'phoneNumber' => '+1987654321'
]);

// Delete a contact
$client->contacts->delete('contact-uuid');

Templates

List and retrieve templates:

// List templates
$result = $client->templates->list();

foreach ($result->data->data as $template) {
    echo $template->name . " (" . $template->status . "): " . $template->id . "\n";
    echo "  Category: " . $template->category . "\n";
}

// Get a specific template
$result = $client->templates->get('template-uuid');

echo "Name: " . $result->data->name . "\n";
echo "Status: " . $result->data->status . "\n";

Making custom or undocumented requests

Undocumented properties

You can send undocumented parameters to any endpoint using the extra* parameters:

$result = $client->messages->send(
    to: ['+1234567890'],
    template: [
        'id' => '7ba7b820-9dad-11d1-80b4-00c04fd430c8',
        'name' => 'welcome'
    ],
    requestOptions: [
        'extraQueryParams' => ['my_query_parameter' => 'value'],
        'extraBodyParams' => ['my_body_parameter' => 'value'],
        'extraHeaders' => ['my-header' => 'value'],
    ],
);

Undocumented endpoints

To make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on:

$response = $client->request(
    method: 'post',
    path: '/undocumented/endpoint',
    query: ['dog' => 'woof'],
    headers: ['useful-header' => 'interesting-value'],
    body: ['hello' => 'world']
);

Laravel Integration

Service Provider (example)

// config/app.php
'providers' => [
    // ...
    App\Providers\SentDMServiceProvider::class,
],

// app/Providers/SentDMServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use SentDM\Client;

class SentDMServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(Client::class, function ($app) {
            return new Client(
                apiKey: config('services.sent_dm.api_key'),
            );
        });
    }
}
// config/services.php
return [
    // ...
    'sent_dm' => [
        'api_key' => env('SENT_DM_API_KEY'),
    ],
];

Dependency Injection

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use SentDM\Client;

class MessageController extends Controller
{
    protected $client;

    public function __construct(Client $client)
    {
        $this->client = $client;
    }

    public function send(Request $request)
    {
        $result = $this->client->messages->send(
            to: [$request->input('phone_number')],
            template: [
                'id' => $request->input('template_id'),
                'name' => 'welcome',
                'parameters' => $request->input('variables', [])
            ]
        );

        if ($result->success) {
            return response()->json([
                'message_id' => $result->data->messages[0]->id,
                'status' => $result->data->messages[0]->status
            ]);
        }

        return response()->json(['error' => $result->error->message], 400);
    }
}

Webhook Handler

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use SentDM\Client;

class WebhookController extends Controller
{
    protected $client;

    public function __construct(Client $client)
    {
        $this->client = $client;
    }

    public function handleSent(Request $request)
    {
        $payload = $request->getContent();
        $signature = $request->header('X-Webhook-Signature');

        // Verify signature
        $isValid = $this->client->webhooks->verifySignature(
            payload: $payload,
            signature: $signature,
            secret: config('services.sent_dm.webhook_secret')
        );

        if (!$isValid) {
            return response()->json(['error' => 'Invalid signature'], 401);
        }

        // Parse and handle event
        $event = json_decode($payload);

        switch ($event->type) {
            case 'message.status.updated':
                \Log::info("Message {$event->data->id} status: {$event->data->status}");
                break;

            case 'message.delivered':
                // Update database
                \DB::table('messages')
                    ->where('sent_id', $event->data->id)
                    ->update(['status' => 'delivered']);
                break;
        }

        return response()->json(['received' => true]);
    }
}

Symfony Integration

# config/packages/sent_dm.yaml
parameters:
    env(SENT_DM_API_KEY): ''

services:
    SentDM\Client:
        arguments:
            $apiKey: '%env(SENT_DM_API_KEY)%'
<?php

namespace App\Controller;

use SentDM\Client;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class MessageController
{
    private $client;

    public function __construct(Client $client)
    {
        $this->client = $client;
    }

    #[Route('/api/send', methods: ['POST'])]
    public function send(Request $request): JsonResponse
    {
        $data = json_decode($request->getContent(), true);

        $result = $this->client->messages->send(
            to: [$data['phone_number']],
            template: [
                'id' => $data['template_id'],
                'name' => 'welcome'
            ]
        );

        if ($result->success) {
            return new JsonResponse([
                'message_id' => $result->data->messages[0]->id,
                'status' => $result->data->messages[0]->status
            ]);
        }

        return new JsonResponse(['error' => $result->error->message], 400);
    }
}

Source & Issues

Getting Help

On this page