Skip to content

PHP

PHP 8.1+. Either the built-in cURL extension (no dependency) or Guzzle for cleaner code in larger projects.

<?php
$apiKey = getenv('LISOLOO_API_KEY');
$apiUrl = '$BASE_URL/api/v1/lisoloo/sms-api';
<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "$apiUrl/send",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"app-key: $apiKey",
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'to' => ['+243998857000'],
'message' => 'Hello from Lisoloo!',
'sender_id' => 'MYAPP',
]),
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status !== 201) {
throw new RuntimeException("Lisoloo error $status: $response");
}
$body = json_decode($response, true);
echo $body['data']['message_id'];
<?php
final class LisolooClient
{
public function __construct(
private string $apiKey,
private string $baseUrl = '$BASE_URL/api/v1/lisoloo/sms-api',
private float $timeout = 10.0,
) {}
/**
* @param string[] $to
* @param array<int, array{date: string, time: string}>|null $scheduledDates
* @param array<string, mixed>|null $recurringSchedule
*/
public function send(
array $to,
string $message,
?string $senderId = null,
string $sendingType = 'immediate',
?array $scheduledDates = null,
?array $recurringSchedule = null,
?string $callbackUrl = null,
): array {
$body = compact('to', 'message') + ['sending_type' => $sendingType];
if ($senderId !== null) $body['sender_id'] = $senderId;
if ($callbackUrl !== null) $body['callback_url'] = $callbackUrl;
if ($scheduledDates !== null) $body['scheduled_dates'] = $scheduledDates;
if ($recurringSchedule !== null) $body['recurring_schedule'] = $recurringSchedule;
return $this->request('POST', '/send', $body)['data'];
}
public function getStatus(string $messageId): array
{
return $this->request('GET', "/status/$messageId")['data'];
}
public function getBalance(): array
{
return $this->request('GET', '/balance')['data'];
}
private function request(string $method, string $path, ?array $body = null): array
{
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $this->baseUrl . $path,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_HTTPHEADER => [
"app-key: $this->apiKey",
'Content-Type: application/json',
],
]);
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$decoded = json_decode((string) $response, true);
if ($status >= 400) {
throw new RuntimeException(
sprintf('Lisoloo %d: %s (%s)',
$status,
$decoded['message'] ?? 'Unknown',
$decoded['error_code'] ?? 'no-code',
),
);
}
return $decoded;
}
}

Usage:

<?php
$client = new LisolooClient(getenv('LISOLOO_API_KEY'));
// Instant
$result = $client->send(['+243998857000'], 'Hello!', 'MYAPP');
// Scheduled
$client->send(
to: ['+243998857000'],
message: 'Reminder',
sendingType: 'scheduled',
scheduledDates: [['date' => '2026-06-01', 'time' => '08:00']],
);
// Recurring
$client->send(
to: ['+243998857000'],
message: 'Weekly',
sendingType: 'recurring',
recurringSchedule: [
'start_date' => '2026-06-01',
'end_date' => '2026-12-31',
'frequency' => 'weekly',
'interval' => 1,
'times' => ['09:00'],
],
);
routes/web.php
<?php
use App\Http\Controllers\LisolooWebhookController;
Route::post('/lisoloo/webhook', LisolooWebhookController::class);
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
final class LisolooWebhookController
{
public function __invoke(Request $req)
{
$auth = $req->header('authorization', '');
if (! str_starts_with($auth, 'Basic ')) {
abort(401);
}
[$user, $pass] = explode(':', base64_decode(substr($auth, 6)), 2);
if (! hash_equals(config('lisoloo.webhook_user'), $user)
|| ! hash_equals(config('lisoloo.webhook_pass'), $pass)) {
abort(401);
}
$event = $req->json()->all();
if (Cache::has("lisoloo:event:{$event['event_id']}")) {
return response()->noContent(); // idempotent replay
}
Cache::put("lisoloo:event:{$event['event_id']}", true, now()->addDays(7));
// … your business logic …
return response()->noContent();
}
}