Getting started
Messaging basics
The rules every send follows: registered sender IDs, number format, message length and character set, recipient limits, your own reference IDs, and how to read the response envelope.
Sender IDs
Every send names a sender in from, and it must be a sender ID registered on your account for that channel and approved (active). For SMS that is the name the recipient sees, 2 to 11 characters; for email it is the address you send from; for WhatsApp it is the number of your WhatsApp sender, and it can be left out when you have only one. The match is case-insensitive, so unicom360 and Unicom360 are the same sender. Register sender IDs in the portal; an unknown one is refused with Invalid From Sender ID (SMS), Invalid Sender (email) or INVALID_SENDER_ID (WhatsApp), and one that is registered but not yet approved with From Sender ID not allowed, Sender not allowed or SENDER_ID_NOT_ALLOWED.
Phone numbers
Give numbers in international format without a plus sign: 260971234567. Two other spellings are accepted and normalised to that form: a leading plus sign (+260971234567) and a local Zambian prefix (0971234567, 0961234567, 0951234567 or 0761234567, to which 26 is added). The response always reports the normalised number, so match on that.
A number that cannot be parsed is not an error for the whole request: it comes back in data with status Invalid mobile number and the other recipients go ahead. Numbers outside Zambia bill against a separate international SMS bundle; see the notes on Send SMS for the limits that apply to them.
Message text
SMS text must use the GSM 7-bit character set: the Latin letters, digits and punctuation on an ordinary keyboard, plus a few accented characters and symbols such as @, £ and €. Emoji, curly quotes and characters from other scripts are outside it, and a message containing any of them is refused with Invalid parameters provided. There is no Unicode (UCS-2) sending on the API.
A message is 1 to 1,200 characters and is billed in 160-character units: up to 160 characters costs one unit per recipient, 161 to 320 costs two, and so on up to eight units for the longest message. Your SMS bundle must cover the whole request for it to be accepted.
Recipients
to takes one number as a string or an array of 1 to 2,000. A request with an empty array or more than 2,000 entries is refused with Recipient list size is invalid and nothing is sent. The same text goes to every recipient in the request; to personalise, send one request per message.
Before anything is written, the gateway checks that your bundle covers the whole request (recipients multiplied by message units). If it does not, the request is refused with INSUFFICIENT_BUNDLE and no part of it is sent.
Your own reference: user_reference_id
user_reference_id is optional, but worth sending on every request that matters. The gateway refuses a reference it has already seen for the same recipient and sender ID, so if your code times out and retries, the retry cannot double-send: it gets duplicate user reference id instead. Use something unique per message on your side, such as an order number or a UUID.
{
"message": "duplicate user reference id",
"success": false,
"api_reference": "1764184470578998353"
}Note what the check covers: the pair of reference and recipient. One reference across a request to several numbers is fine; the same reference to the same number twice is not. The reference is stored with the message and shown in the portal, which also makes it the easiest way to find a message later.
The response envelope
Every JSON send answers with the same four fields:
{
"api_reference": "1764184470578998353",
"data": [
{
"message_id": "dff31690-b450-4000-a6b7-141d8523ef10",
"status": "ACKNOWLEDGED",
"mobile_number": "260971234567"
},
{
"message_id": "dff31690-b450-4001-a6b7-141d8523ef10",
"status": "Invalid mobile number",
"mobile_number": "12345"
}
],
"message": "successful",
"success": true
}| Field | Meaning |
|---|---|
| success | true when the request was accepted; false when it was refused. |
| message | "successful", or the reason for a refusal. |
| data | Only on success: one entry per recipient with message_id, status and the recipient (mobile_number or email_address). Match entries to recipients by that field, not by position: past ten recipients they do not come back in the order sent. |
| api_reference | Identifies this request in the gateway's logs. Quote it when asking support about a call. |
success
- Meaning
- true when the request was accepted; false when it was refused.
message
- Meaning
- "successful", or the reason for a refusal.
data
- Meaning
- Only on success: one entry per recipient with message_id, status and the recipient (mobile_number or email_address). Match entries to recipients by that field, not by position: past ten recipients they do not come back in the order sent.
api_reference
- Meaning
- Identifies this request in the gateway's logs. Quote it when asking support about a call.
Business errors are HTTP 200
Check success, not the status code
A refusal the gateway can explain (unknown sender ID, empty bundle, reused reference, bad recipient list) is answered with HTTP 200 and success: false. Only malformed requests (400), authentication (401, 429) and gateway failures (5xx) use the status code. A client that treats every 200 as sent will miss refusals.
The balance endpoints are the exception to the envelope: they answer with status rather than success. See Balance. The WhatsApp endpoints keep the four fields but shape data differently: an object with accepted, rejected and a results list on a template send, and the single message on a session send. Their refusals are upper-case codes and their 400s are sentences naming the field. See WhatsApp.
Delivery status
ACKNOWLEDGED means the gateway accepted the message, not that the handset has it. Delivery status arrives later, per message, on the callback_url you give with the request, and is shown in the portal. See Delivery webhooks.