PHP SDK
The official PHP SDK for Sent 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-phpTo 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 DashboardSend 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:
| Cause | Error Type |
|---|---|
| HTTP 400 | BadRequestException |
| HTTP 401 | AuthenticationException |
| HTTP 403 | PermissionDeniedException |
| HTTP 404 | NotFoundException |
| HTTP 409 | ConflictException |
| HTTP 422 | UnprocessableEntityException |
| HTTP 429 | RateLimitException |
| HTTP >= 500 | InternalServerException |
| Other HTTP error | APIStatusException |
| Timeout | APITimeoutException |
| Network error | APIConnectionException |
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
- Version: 0.6.0
- GitHub: sentdm/sent-dm-php
- Packagist: sentdm/sent-dm-php
- Issues: Report a bug
Getting Help
- Documentation: API Reference
- Troubleshooting: Common Issues
- Support: Email support@sent.dm with your request ID