SMS API Documentation
Base URL: https://{host}
https://api.sms.com.na (SaaS),
https://sms.yourcompany.com (Enterprise OnSite)
The SMS API allows you to send SMS messages, retrieve delivery reports, view message logs, and manage scheduled messages programmatically.
Authentication
All API requests require authentication using an API key in the Authorization header:
Authorization: YOUR_API_KEY
Getting Your API Key
- Log in to the SMSDESK Portal
- Navigate to Settings → API Keys
- Generate a new API key or copy your existing key
Send SMS Messages
POST /sms/2/messages
Send one or more SMS messages to specified destinations.
Request Headers
| Header | Value | Required |
|---|---|---|
Authorization |
YOUR_API_KEY | Yes |
Content-Type |
application/json | Yes |
Request Body
{
"bulkId": "BULK-20260701-001",
"messages": [
{
"from": "YourBrand",
"destinations": [
{"to": "+264811234567"},
{"to": "+264812345678"}
],
"text": "Your message text here",
"sendAt": "2026-07-01T15:00:00.000Z",
"options": {
"flash": false
},
"includeSmsCountInResponse": true
}
]
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
bulkId |
string | No | Unique identifier for this batch of messages |
from |
string | No | Sender ID (defaults to your account's assigned channel if not specified) |
destinations |
array | Yes | Array of recipient objects with "to" field |
to |
string | Yes | Recipient phone number (E.164 format: +264811234567 or 264811234567) |
messageId |
string | No | Custom message ID for tracking (auto-generated if not provided) |
text |
string | Yes | Message content. Messages longer than 160 GSM characters (70 UCS2 characters) are automatically split into concatenated parts (153 GSM / 67 UCS2 per part). Each part is billed separately by the network. |
notifyUrl |
string | No | Webhook URL for delivery reports |
notifyContentType |
string | No | application/json or application/x-www-form-urlencoded |
sendAt |
string | No | Schedule message for future delivery (ISO 8601 format: 2026-07-01T15:00:00.000Z) |
options.flash |
boolean | No | Send as flash SMS (appears as popup on phone) |
includeSmsCountInResponse |
boolean | No | Include SMS part count in response |
Response (200 OK)
{
"bulkId": "BULK-20260701-001",
"messages": [
{
"to": "+264811234567",
"from": "33333",
"messageId": "12345678-1234-1234-1234-123456789012",
"smsCount": 1,
"status": {
"groupId": 1,
"groupName": "PENDING",
"id": 26,
"name": "PENDING_ACCEPTED",
"description": "Message sent to next instance"
}
},
{
"to": "+264812345678",
"from": "33333",
"messageId": "12345678-1234-1234-1234-123456789013",
"smsCount": 1,
"status": {
"groupId": 1,
"groupName": "PENDING",
"id": 26,
"name": "PENDING_ACCEPTED",
"description": "Message sent to next instance"
}
}
]
}
cURL Example
curl -X POST https://{host}/sms/2/messages \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [{
"destinations": [{"to": "+264811234567"}],
"text": "Hello from SMSDESK!"
}]
}'
Long Messages
Messages longer than 160 GSM characters (or 70 UCS2 characters for Unicode) are automatically split into concatenated SMS parts and reassembled on the recipient's handset. Each part is billed separately by the mobile network. The GSM maximum is 255 parts per message (39,015 GSM characters or 17,085 Unicode characters); longer text is rejected with a validation error and nothing is queued. Mobile networks may accept fewer parts than the GSM maximum.
| Encoding | Single SMS | Per concatenated part |
|---|---|---|
| GSM 7-bit (default Latin alphabet) | 160 characters | 153 characters |
| UCS2 (Unicode, e.g. emoji, non-Latin scripts) | 70 characters | 67 characters |
GSM extension characters ({ } [ ] \ ~ ^ | €) count as 2 characters each. A single
non-GSM character (such as an emoji or smart quote) switches the entire message to UCS2 encoding.
Message Priority
Messages are dispatched to the mobile networks in priority order (CRITICAL,
HIGH, NORMAL, LOW, BULK), and in the order received
within the same priority. Requests made through this API default to HIGH, ahead of SMPP
(NORMAL), portal and email-to-SMS (LOW) and CSV/bulk uploads
(BULK).
Your account administrator can override the priority for each user in the web portal (for example,
CRITICAL for an OTP application and BULK for a marketing application).
Create a dedicated API-only user per application to keep OTP, transactional and bulk traffic separate.
Priority changes the dispatch order only; it never throttles or rejects messages.
Acceptance vs. delivery
A 200 OK response confirms that SMSDESK has accepted and queued the message
(status group PENDING, PENDING_ACCEPTED). It does not confirm that the mobile network or the handset has
received it. Use the delivery reports and
message logs endpoints to follow a message through queue, network and
delivery states. Some networks do not return handset-level delivery reports.
Delivery Reports
GET /sms/2/reports
Retrieve delivery reports for sent messages. Use this endpoint to check the delivery status of your SMS messages.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
smsId |
integer | No | Filter by internal SMS ID (from sms_outgoing.id) to get detailed status |
messageId |
string | No | Filter by external message ID (axid) to check status of a single message |
bulkId |
string | No | Filter by bulk ID to get reports for all messages in a batch |
limit |
integer | No | Max number of reports to return (default: 50, max: 1000) |
Response (200 OK)
{
"results": [
{
"smsId": 123456,
"bulkId": "BULK-20260701-001",
"messageId": "12345678-1234-1234-1234-123456789012",
"to": "264811234567",
"sentAt": "2026-06-25T10:30:00.000+0000",
"doneAt": "2026-06-25T10:30:05.000+0000",
"scheduledTime": null,
"smsCount": 1,
"price": {
"pricePerMessage": 0.50,
"currency": "NAD"
},
"statusCode": 3,
"axStatusDesk": "DELIVRD",
"status": {
"groupId": 3,
"groupName": "DELIVERED",
"id": 5,
"name": "DELIVERED",
"description": "Message delivered to handset"
},
"error": null
}
]
}
cURL Examples
Get all recent delivery reports:
curl -X GET "https://{host}/sms/2/reports?limit=100" \
-H "Authorization: YOUR_API_KEY"
Check status by internal SMS ID:
curl -X GET "https://{host}/sms/2/reports?smsId=123456" \
-H "Authorization: YOUR_API_KEY"
Check status by external message ID:
curl -X GET "https://{host}/sms/2/reports?messageId=12345678-1234-1234-1234-123456789012" \
-H "Authorization: YOUR_API_KEY"
Get delivery reports for a bulk batch:
curl -X GET "https://{host}/sms/2/reports?bulkId=BULK-20260701-001" \
-H "Authorization: YOUR_API_KEY"
Message Logs
GET /sms/2/logs
View logs of sent messages with filtering options.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
from |
string | Filter by sender ID |
to |
string | Filter by recipient number |
limit |
integer | Max results (default: 50, max: 1000) |
Response (200 OK)
{
"results": [
{
"messageId": "12345678-1234-1234-1234-123456789012",
"to": "264811234567",
"from": "YourBrand",
"text": "Hello from SMSDESK!",
"sentAt": "2026-06-25T10:30:00.000+0000",
"status": {
"groupId": 3,
"groupName": "DELIVERED",
"id": 5,
"name": "DELIVERED_TO_HANDSET"
},
"smsCount": 1,
"price": {
"pricePerMessage": 0.50,
"currency": "NAD"
}
}
]
}
cURL Example
curl -X GET "https://{host}/sms/2/logs?limit=50" \
-H "Authorization: YOUR_API_KEY"
Message Preview
POST /sms/2/preview
Preview message details before sending (character count, number of SMS parts, etc.).
Request Body
{
"text": "Your message text here"
}
Response (200 OK)
{
"originalText": "Your message text here",
"textPreview": "Your message text here",
"messageCount": 1,
"charactersRemaining": 137,
"configuration": {
"language": {
"languageCode": "EN"
},
"transliteration": null
}
}
Scheduled Messages
GET /sms/2/bulks
PUT /sms/2/bulks - Reschedule
messages
DELETE /sms/2/bulks - Cancel
scheduled messages
View scheduled messages that are queued for future delivery.
Response (200 OK)
{
"bulks": [
{
"bulkId": "bulk-12345",
"sendAt": "2026-06-26T09:00:00.000+0000"
}
]
}
Error Codes
The API uses standard HTTP status codes and returns detailed error messages in JSON format.
Common Error Responses
| Status Code | Error | Description |
|---|---|---|
| 400 | Bad Request | Invalid request parameters or malformed JSON |
| 401 | Unauthorized | Invalid or missing API key |
| 403 | Forbidden | Insufficient credits or permissions |
| 429 | Too Many Requests | Rate limit exceeded (300 requests/minute) |
| 500 | Internal Server Error | Server error - contact support |
Error Response Format
{
"requestError": {
"serviceException": {
"messageId": "BAD_REQUEST",
"text": "Invalid request parameters",
"validationErrors": {
"from": "Sender ID is required"
}
}
}
}
Code Examples
Python Example
import requests
import json
url = "https://{host}/sms/2/messages"
headers = {
"Authorization": "YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"messages": [{
"from": "YourBrand",
"destinations": [{"to": "264811234567"}],
"text": "Hello from Python!"
}]
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
PHP Example
<?php
$url = "https://{host}/sms/2/messages";
$data = [
"messages" => [[
"from" => "YourBrand",
"destinations" => [["to" => "264811234567"]],
"text" => "Hello from PHP!"
]]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: YOUR_API_KEY",
"Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
JavaScript (Node.js) Example
const axios = require('axios');
const url = 'https://{host}/sms/2/messages';
const headers = {
'Authorization': 'YOUR_API_KEY',
'Content-Type': 'application/json'
};
const data = {
messages: [{
from: 'YourBrand',
destinations: [{to: '264811234567'}],
text: 'Hello from Node.js!'
}]
};
axios.post(url, data, {headers})
.then(response => console.log(response.data))
.catch(error => console.error(error));
C# Example
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "YOUR_API_KEY");
var json = @"{
""messages"": [{
""from"": ""YourBrand"",
""destinations"": [{""to"": ""264811234567""}],
""text"": ""Hello from C#!""
}]
}";
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://{host}/sms/2/messages", content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
