Authentication
Your API key is under Developer / API in the portal (you can view it any time, and reset it if it leaks). Send it with every request in one of these ways (the header is recommended):
Authorization: Bearer avc_xxxxxxxxxxxxxxxx
X-API-Key: avc_xxxxxxxxxxxxxxxx
?api_key=avc_xxxxxxxxxxxxxxxx # query string, for simple GET integrationsResponses
Every reply is JSON. Success replies have "status": "success" and a data object. Errors have "status": "error", a message and the HTTP code below.
Error codes
| Code | Meaning |
|---|---|
| 400 | Bad request: missing to or message, or no valid numbers |
| 401 | Missing or invalid API key |
| 402 | Insufficient balance. Top up in the portal |
| 403 | Account suspended, API disabled, or IP not allowed |
| 404 | Message or campaign not found |
| 422 | Rejected: unapproved sender ID, bad schedule time, etc. |
| 429 | Rate limit exceeded |
Send SMS
POST/api/v1/sms/send Also accepts GET with query parameters.
| Field | Required | Description |
|---|---|---|
to | yes | One number, a comma-separated list, a JSON array, or an array of {"to": "0771234567", "name": "Nimal"} objects for personalisation. Formats: 0771234567, 771234567, 94771234567, +94771234567. Up to 10,000 per request. Duplicates and blocked numbers are dropped. |
message | yes | Text, up to 1000 characters. Sinhala/Tamil are detected automatically and sent as Unicode (70 chars per part; English 160). {name} is replaced per recipient when names are given. |
name_fallback | no | Text used for {name} when a recipient has no name (default: empty). |
sender_id | no | An approved sender ID on your account. Defaults to your default sender. |
schedule_at | no | Send later, Sri Lanka time, e.g. 2026-10-12 09:30. |
ref | no | Your own reference (order no. etc., max 64 chars). Returned in status replies and webhooks. |
callback_url | no | HTTPS URL that receives the delivery report for these messages (overrides the account webhook). |
async | no | 1 to always queue and reply immediately. Small sends are otherwise delivered to the network before the reply. |
curl -X POST https://avcsms.lk/api/v1/sms/send \ -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"to": ["0771234567","0712345678"], "message": "Your OTP is 482913", "sender_id": "MYSHOP", "ref": "login-4821"}'
$ch = curl_init('https://avcsms.lk/api/v1/sms/send'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode(['to' => '0771234567', 'message' => 'Hello!', 'ref' => 'order-77']), ]); $reply = json_decode(curl_exec($ch), true); if (($reply['status'] ?? '') === 'success') { /* $reply['data']['messages'][0]['id'] */ }
const r = await fetch("https://avcsms.lk/api/v1/sms/send", { method: "POST", headers: { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" }, body: JSON.stringify({ to: "0771234567", message: "Hello!" }) }); console.log(await r.json());
import requests r = requests.post("https://avcsms.lk/api/v1/sms/send", headers={"Authorization": "Bearer YOUR_API_KEY"}, json={"to": "0771234567", "message": "ඔබේ OTP 482913"}) print(r.status_code, r.json())
https://avcsms.lk/api/v1/sms/send?api_key=YOUR_API_KEY&to=0771234567&message=Hello
For tools that cannot POST. Keep keys out of shared URLs where you can.
Reply 201
{
"status": "success",
"data": {
"campaign_id": 120, "sender_id": "MYSHOP", "type": "plain", "segments": 1,
"accepted": 2, "invalid": [], "blocked": 0, "cost": 2.00, "balance": 4318.00, "scheduled_at": null,
"messages": [ {"id": 9001, "to": "94771234567", "status": "sent", "cost": 1.00},
{"id": 9002, "to": "94712345678", "status": "sent", "cost": 1.00} ]
}
}Message status
GET/api/v1/sms/{id}
{ "status": "success", "data": { "id": 9001, "campaign_id": 120, "to": "94771234567", "sender_id": "MYSHOP",
"message": "Your OTP is 482913", "type": "plain", "segments": 1, "cost": 1.00, "status": "delivered", "error": null,
"ref": "login-4821", "created_at": "2026-10-10 14:02:11", "scheduled_at": null, "sent_at": "2026-10-10 14:02:12", "delivered_at": "2026-10-10 14:02:20" } }sent means accepted by the network. cancelled appears when you cancel a scheduled send.
List messages
GET/api/v1/sms
Filters: ref, campaign_id, status, to, from (date), to_date, page, per_page (max 200). The reply has page, per_page, total and messages.
Campaign summary
GET/api/v1/campaigns/{id}
Totals for a bulk send: sent, delivered, failed and cost.
Balance
GET/api/v1/balance
{ "status": "success", "data": { "balance": 4318.00, "currency": "LKR", "rate_per_sms": 1.00, "approx_sms": 4318 } }Sender IDs
GET/api/v1/sender-ids
Your sender IDs and their approval status.
Count parts before sending
POST/api/v1/count
Send message. The reply has type, length, segments, per_segment and cost_per_recipient at your rate.
Delivery webhook
Set a webhook URL in the portal, or pass callback_url with a send. When a message reaches a final state we POST:
POST https://yoursite.lk/sms-status Content-Type: application/json { "event": "sms.status", "id": 9001, "ref": "login-4821", "to": "94771234567", "sender_id": "MYSHOP", "status": "delivered", "sent_at": "2026-10-10 14:02:12", "delivered_at": "2026-10-10 14:02:20", "error": null }
Reply with HTTP 200. Reports are sent once, so use GET /api/v1/sms/{id} to reconcile.
Good to know
- Billing is per message part at your account rate. English up to 160 characters = 1 part (153 per part after that); Sinhala/Tamil 70 (67 after).
- Numbers must be Sri Lankan mobiles (Dialog, Mobitel, Hutch, Airtel). Others are reported in
invalidand not charged. - Messages the network refuses are refunded automatically.
- Need help? info@avc.lk · 0701863408