Keep the API key out of your code
Store the key in an environment variable or your framework configuration, not in a file that goes to Git. The examples read it from AVCSMS_API_KEY. In the portal you can also restrict the key to the IP address of your server.
Send one SMS
One function covers every kind of send. It posts JSON to the send endpoint and returns the data part of the reply, or throws an exception with the reason.
<?php
function send_sms(string|array $to, string $message, array $extra = []): array
{
$ch = curl_init('https://avcsms.lk/api/v1/sms/send');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('AVCSMS_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['to' => $to, 'message' => $message] + $extra),
]);
$body = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$reply = json_decode((string) $body, true) ?: [];
if ($code !== 201) {
throw new RuntimeException($reply['message'] ?? "SMS request failed (HTTP $code)");
}
return $reply['data'];
}
$result = send_sms('0771234567', 'Your order #1042 is ready for pick-up.');
echo $result['messages'][0]['id']; // keep this ID to check delivery laterA successful reply has HTTP status 201 and tells you the cost, the number of parts, your new balance and an ID for each message. Numbers can be written as 0771234567, 94771234567 or +94771234567.
Send to many numbers, with names
Pass an array of numbers to send the same text to all of them, up to 10,000 in one request. To personalise it, pass name-and-number pairs and write {name} in the message.
$result = send_sms(
[
['to' => '0771234567', 'name' => 'Nimal'],
['to' => '0712345678', 'name' => 'Kumari'],
],
'Hi {name}, your November invoice is ready.',
['sender_id' => 'MYSHOP', 'ref' => 'invoice-nov']
);
echo "Accepted {$result['accepted']} messages, cost Rs. {$result['cost']}";The optional fields are sender_id (an approved sender ID on your account), ref (your own reference, returned in status replies), schedule_at (a date and time in Sri Lanka time, such as 2026-12-01 09:30) and callback_url (where the delivery report should go).
Check whether a message was delivered
function sms_status(int $id): array
{
$ch = curl_init("https://avcsms.lk/api/v1/sms/$id");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AVCSMS_API_KEY')],
]);
$reply = json_decode((string) curl_exec($ch), true);
return $reply['data'];
}
echo sms_status(9001)['status']; // queued, sending, sent, delivered or failedReceive delivery reports on your server
Instead of asking for the status, let the API tell you. Set a webhook URL on the Developer / API page, or pass callback_url with a send. When a message is delivered or fails, this script receives a JSON report.
<?php // sms-status.php
$report = json_decode(file_get_contents('php://input'), true);
if (($report['event'] ?? '') === 'sms.status') {
// $report['id'], $report['ref'], $report['to'], $report['status']
// update the order or login record that matches the reference
}
http_response_code(200);Laravel
In Laravel the HTTP client does the same job in a few lines. Put the key in config/services.php and read it from the environment.
use Illuminate\Support\Facades\Http;
$response = Http::withToken(config('services.avcsms.key'))
->post('https://avcsms.lk/api/v1/sms/send', [
'to' => '0771234567',
'message' => 'Your OTP is 482913',
]);
if ($response->failed()) {
logger()->error('SMS failed: ' . $response->json('message'));
}
$messageId = $response->json('data.messages.0.id');Errors you should handle
| HTTP code | What it means | What to do |
|---|---|---|
| 400 | A field is missing, or no number in the request is a valid Sri Lankan mobile | Fix the request |
| 401 | The API key is missing or wrong | Check the key and the Authorization header |
| 402 | The balance is too low for this send | Top up, then send again |
| 422 | The sender ID is not approved, or the schedule time is not valid | Use an approved sender ID or a future time |
| 429 | More than 120 requests in a minute from one key | Wait a moment and retry |
The full list of endpoints and fields is in the SMS API reference. If you are building login codes, read how to add OTP verification by SMS next.