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';Send an SMS
Section titled “Send an SMS”<?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
use GuzzleHttp\Client;
$client = new Client([ 'base_uri' => $apiUrl, 'headers' => [ 'app-key' => $apiKey, 'Content-Type' => 'application/json', ], 'timeout' => 10.0,]);
$response = $client->post('/send', [ 'json' => [ 'to' => ['+243998857000'], 'message' => 'Hello from Lisoloo!', 'sender_id' => 'MYAPP', ],]);
$body = json_decode((string) $response->getBody(), true);echo $body['data']['message_id'];A reusable client class
Section titled “A reusable client class”<?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'], ],);Laravel webhook receiver
Section titled “Laravel webhook receiver”<?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(); }}