📡 API Documentation
TellbySMS Communications provides a simple REST API that lets you send SMS, manage contacts and query your account from any programming language.
Every request must include your API token. Get your token by creating a free account and visiting the API Access page.
Send your token using the Authorization header (recommended):
Authorization: Bearer YOUR_API_TOKEN
Or as a query string parameter:
https://sms.scopehost.net/api/v1/?endpoint=balance&api_token=YOUR_API_TOKEN
All responses are JSON. Every response includes a status field.
{"status": "success", "message": "...", "data": [...]}
{"status": "error", "message": "Reason for failure"}
| HTTP | status | Meaning |
|---|---|---|
200 | success | Request completed successfully |
400 | error | Missing or invalid parameters |
401 | error | Invalid or missing API token |
402 | error | Insufficient credits |
404 | error | Unknown endpoint |
405 | error | Wrong HTTP method |
| Parameter | Required | Type | Description |
|---|---|---|---|
email |
Required | string | Your account email address |
password |
Required | string | Your account password |
$result = api('login', 'POST', [
'email' => '[email protected]',
'password' => 'yourpassword',
]);
$token = $result['api_token'];
{"status":"success","api_token":"3b03e0a3...","user":{"id":1,"name":"John Dlamini","email":"[email protected]"}}
$balance = api('balance');
echo "Balance: " . $balance['currency'] . $balance['balance'];
{"status":"success","balance":231.98,"currency":"E"}
$stats = api('stats');
echo "Sent: " . $stats['stats']['sent'];
echo "Balance: E" . $stats['balance'];
{"status":"success","balance":231.98,"stats":{"sent":1420,"failed":3,"scheduled":2,"contacts":98},"chart":[{"date":"19 Apr","count":42},{"date":"20 Apr","count":87}]}
| Parameter | Required | Type | Description |
|---|---|---|---|
to |
Required | string | Phone number(s) comma-separated, or group:{id} to send to an entire group |
message |
Required | string | SMS text (max 612 chars). Supports {name} {mobile} personalisation |
sender_id |
Optional | string | Approved Sender ID (e.g. MyBrand). Leave blank for default |
scheduled_at |
Optional | datetime | Schedule delivery: YYYY-MM-DD HH:MM |
$result = api('send', 'POST', [
'to' => '26876123456,26878654321',
'message' => 'Hi {name}, your order is ready!',
]);
// Send to entire group
$result = api('send', 'POST', [
'to' => 'group:3',
'message' => 'Special offer for VIP members!',
]);
{"status":"success","message":"SMS sent to 3 recipient(s)","msg_id":42}
| Parameter | Required | Type | Description |
|---|---|---|---|
page |
Optional | int | Page number (default: 1) |
limit |
Optional | int | Results per page (default: 20, max: 100) |
status |
Optional | string | Filter: sent failed queued all |
$messages = api('messages', 'GET', ['page' => 1, 'status' => 'sent']);
foreach ($messages['data'] as $msg) {
echo $msg['id'] . " → " . $msg['status'];
}
{"status":"success","total":142,"data":[{"id":42,"recipients":"26876123456","message":"Hello!","status":"sent","credits_used":0.40,"sent_at":"2026-04-25 10:30:00"}]}
| Parameter | Required | Type | Description |
|---|---|---|---|
group_id |
Optional | int | Filter contacts by group ID |
$contacts = api('contacts', 'GET', ['group_id' => 2]);
foreach ($contacts['data'] as $c) {
echo $c['name'] . " — " . $c['mobile'];
}
{"status":"success","data":[{"id":1,"name":"Jane Dlamini","mobile":"26876123456","group_id":2}]}
| Parameter | Required | Type | Description |
|---|---|---|---|
mobile |
Required | string | Phone number (e.g. 26876123456) |
name |
Optional | string | Contact name |
group_id |
Optional | int | Assign to a group |
$result = api('contacts', 'POST', [
'mobile' => '26876123456',
'name' => 'Jane Dlamini',
'group_id' => 2,
]);
{"status":"success","message":"Contact added","id":15}
| Parameter | Required | Type | Description |
|---|---|---|---|
id |
Required | int | Contact ID to delete |
$result = api('contacts', 'DELETE', ['id' => 15]);
{"status":"success","message":"Contact deleted"}
$groups = api('groups');
foreach ($groups['data'] as $g) {
echo $g['name'] . " (" . $g['contact_count'] . " contacts)";
}
{"status":"success","data":[{"id":2,"name":"VIP Customers","contact_count":45}]}
| Parameter | Required | Type | Description |
|---|---|---|---|
name |
Required | string | Group name |
description |
Optional | string | Group description |
$result = api('groups', 'POST', [
'name' => 'VIP Customers',
'description' => 'Top tier clients',
]);
{"status":"success","message":"Group created","id":3}
$senderIds = api('sender_ids');
foreach ($senderIds['data'] as $s) {
echo $s['sender_id'] . " — " . $s['status'];
}
{"status":"success","data":[{"id":1,"sender_id":"MyBrand","status":"approved"}]}
| Parameter | Required | Type | Description |
|---|---|---|---|
sender_id |
Required | string | Desired Sender ID (max 11 chars, no spaces) |
description |
Optional | string | Business reason for this Sender ID |
$result = api('sender_ids', 'POST', [
'sender_id' => 'MyBrand',
'description' => 'Customer notifications for MyBrand eCommerce',
]);
{"status":"success","message":"Application submitted. Pending review."}
$profile = api('profile');
echo $profile['data']['name'] . " — E" . $profile['data']['credits'];
{"status":"success","data":{"name":"John Dlamini","email":"[email protected]","phone":"26876123456","credits":231.98}}
| Parameter | Required | Type | Description |
|---|---|---|---|
name |
Optional | string | Your display name |
phone |
Optional | string | Your phone number |
$result = api('profile', 'POST', [
'name' => 'John Dlamini',
'phone' => '26876123456',
]);
{"status":"success","message":"Profile updated"}
| Parameter | Required | Type | Description |
|---|---|---|---|
page |
Optional | int | Page number (default: 1) |
$txns = api('transactions', 'GET', ['page' => 1]);
foreach ($txns['data'] as $t) {
$sign = $t['type'] === 'credit' ? '+' : '-';
echo $sign . "E" . $t['amount'] . " — " . $t['description'];
}
{"status":"success","data":[{"id":10,"type":"credit","amount":50.00,"description":"Top up via MoMo","created_at":"2026-04-20 14:00:00"}]}
Retrieve delivery status for individual messages. The platform polls from the gateway every 15 minutes and updates statuses automatically.
Returns per-recipient delivery status for a message.
| Parameter | Type | Required | Description |
|---|---|---|---|
| message_id | integer | Yes | The message ID to check |
Response
{
"status": "success",
"message_id": 1234,
"overall_status": "delivered",
"recipients": [
{
"number": "26876123456",
"status": "delivered",
"updated_at": "2026-04-30T12:05:00"
},
{
"number": "26878654321",
"status": "pending",
"updated_at": null
}
]
}
Delivery statuses: pending — not yet confirmed · delivered — confirmed delivered · failed — delivery failed · rejected — rejected by carrier · expired — TTL expired
The API enforces rate limits to ensure fair usage across all clients. When a limit is exceeded, the API returns HTTP 429 Too Many Requests.
Rate limit headers are included with every response:
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 54 X-RateLimit-Limit-Hour: 1000 X-RateLimit-Remaining-Hour: 987
When rate limited, the response includes a Retry-After header indicating how many seconds to wait:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
{
"status": "error",
"message": "Rate limit exceeded. Max 1000 requests per minute. Retry after 60 seconds."
}
Configure webhook endpoints from your dashboard at /webhooks. TellbySMS will POST a JSON payload to your URL when events occur.
Supported events
| Event | Fired when |
|---|---|
sms_sent | An SMS is successfully sent |
delivery | Delivery status updated for a message |
low_balance | Account balance drops below threshold |
credit_added | Credits are added to account |
ping | Manual test ping from dashboard |
Payload format
{
"event": "sms_sent",
"timestamp": "2026-04-30T12:00:00+02:00",
"data": {
"message_id": 1234,
"recipients": 50,
"status": "sent"
}
}
Signature verification
When a secret is configured, each request includes a X-TellbySMS-Signature header with an HMAC-SHA256 signature. Always verify this in production:
// Verify webhook signature function verifyWebhook(string $secret): bool { $rawBody = file_get_contents('php://input'); $sigHeader = $_SERVER['HTTP_X_TELLBYSMS_SIGNATURE'] ?? ''; $expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret); return hash_equals($expected, $sigHeader); } // In your webhook handler: if (!verifyWebhook('your-webhook-secret')) { http_response_code(401); exit('Invalid signature'); } $payload = json_decode(file_get_contents('php://input'), true);
Webhooks are automatically disabled after 10 consecutive delivery failures. Re-enable from your dashboard.
Use this reusable function to call any API endpoint. Download the full examples file for 17 pre-built examples.
// Include this in your project function api(string $endpoint, string $method = 'GET', array $data = []): array { $url = 'https://sms.scopehost.net/api/v1/?endpoint=' . $endpoint; if ($method === 'GET' && !empty($data)) { $url .= '&' . http_build_query($data); } $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30, CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_TOKEN'], ]); if ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); } $response = curl_exec($ch); curl_close($ch); return json_decode($response, true) ?? []; }