● REST API · v1

Send SMS from your own system

A plain JSON-over-HTTPS API built for South African businesses. Sign in with your key, send up to 500 messages in one call, and get delivery results and replies posted straight back to you.

Quick start

From zero to your first message in three steps.

1
Create an API keyIn your portal under Settings, team & API → API keys. You get a client ID and a secret.
2
Sign in for a tokenExchange your key for a token that lasts 24 hours. Reuse it on every call.
3
SendPost your messages. We reply with the cost and what was accepted.
Test mode is free. Add "testMode": true to any send to check the call and see the cost — nothing is sent and nothing is charged.

GETAuthentication

Send your client ID and secret as HTTP Basic authentication. You get back a token valid for 24 hours; use it on every other call as Authorization: Bearer <token>. When a call answers 401, sign in again.

# exchange your key for a 24-hour token
curl -u CLIENT_ID:SECRET https://api.staging.all-telecoms.co.za/v1/Authentication

{"token": "eyJhbGciOi...", "schema": "JWT", "expiresInMinutes": 1440}

At most 60 sign-ins per 15 minutes from one IP address — keep the token and reuse it.

POSTSend messages

Post 1 to 500 messages in a single call. We reply with how many will send, the credits used, and your balance afterward.

curl -X POST https://api.staging.all-telecoms.co.za/v1/BulkMessages \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "sendOptions": {
    "senderId": "MyShop"
  },
  "messages": [
    {
      "destination": "0821234567",
      "content": "Your order 1001 is ready.",
      "customerId": "order-1001"
    },
    {
      "destination": "0831234567",
      "content": "Your order 1002 is ready.",
      "customerId": "order-1002"
    }
  ]
}'

The response

{
  "eventId": 712,
  "messages": 2,
  "parts": 2,
  "cost": 2,
  "remainingBalance": 1250.4,
  "sample": "Your order 1001 is ready.",
  "costBreakdown": [
    {
      "quantity": 2,
      "cost": 2,
      "network": "all"
    }
  ],
  "errorReport": {
    "noNetwork": 0,
    "noContents": 0,
    "duplicates": 0,
    "optedOuts": 0,
    "faults": []
  }
}
FieldWhat it is
messages1 to 500 messages per call.
destinationThe phone number. Accepts 0821234567, 27821234567 or +27821234567.
contentThe text, up to 3 SMS parts (459 characters, or 201 with special characters).
customerIdOptional: your own reference (up to 100 characters). It comes back with the delivery result and with replies.
sendOptions.senderIdOptional: the sender name or number (up to 15 characters), if one is set up for your account.
sendOptions.testModeOptional: true checks the call and works out the cost, but sends and charges nothing.
Safe to retry. A call is accepted completely or not at all. If you get no answer, send the exact same call again within 10 minutes — you get the first answer back and nothing is ever sent twice.

Try it live

Test mode · nothing is sent

Edit the request and run it. Preview prices it with no key; Run in test mode signs in with your own key and prices it against the live API. Neither sends a real SMS or charges credit.

GETBalance

Check your remaining credit at any time.

curl -H "Authorization: Bearer TOKEN" https://api.staging.all-telecoms.co.za/v1/Balance

{"balance": 1250.40, "currency": "ZAR"}

Delivery results & replies

Give us your system's HTTPS address and we POST JSON to it the moment each message reaches its final result, and whenever someone replies. Answer with any 2xx within 10 seconds; otherwise we retry over about a day (1, 5, 15, 30 min, then 1, 2, 4, 8, 12 h). Redirects aren't followed.

{
  "id": "1843",
  "type": "delivery",
  "messageId": "99120",
  "customerId": "order-1001",
  "sendId": "4410",
  "eventId": "712",
  "phoneNumber": "+27821234567",
  "status": "DELIVERED",
  "networkStatus": "DELIVRD",
  "mcc": "655",
  "mnc": "01",
  "handsetTime": "2026-10-01T08:15:01Z",
  "parts": 1,
  "time": "2026-10-01T08:15:02Z"
}

status is DELIVERED or FAILED. networkStatus, mcc/mnc (the mobile network) and handsetTime are what the network reported, when known.

{
  "id": "1844",
  "type": "reply",
  "replyId": "551",
  "phoneNumber": "+27821234567",
  "text": "STOP",
  "optOut": true,
  "replyToMessageId": "99120",
  "replyToCustomerId": "order-1001",
  "time": "2026-10-01T08:20:40Z"
}
Opt-outs are automatic. When optOut is true, we've already stopped sending to that person from your account — you don't have to do anything.

Checking it came from us

Every call carries an X-AT-Signature header: t=<unix seconds>,v1=<signature>, where the signature is the hex HMAC-SHA256 of <t>.<raw request body> with your signing secret (in Settings, starts with whsec_). Refuse calls whose t is more than 5 minutes old. The X-AT-Delivery header is the notification's id: the same one can arrive twice, so ignore an id you've already handled.

import { createHmac, timingSafeEqual } from "node:crypto";

function genuine(rawBody, header, secret) {
  const [, t, v1] = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? "") ?? [];
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(t + "." + rawBody).digest();
  return timingSafeEqual(expected, Buffer.from(v1, "hex"));
}

Error codes

Errors answer with an HTTP status and {"errorCode": ..., "errorMessage": "..."}.

StatusCodeMeaningWhat to do
4001000–1006Something in the call isn't right (the message says what).Fix the call. Nothing was sent.
4011401Wrong client ID or secret, or the token has expired.Sign in again.
4021402Not enough credit for the whole call.Top up. Nothing was sent.
4031403The account isn't set up for sending yet.Contact us.
4031404The call came from an IP address not allowed for this key.Add the address under Allowed from.
4031405The account's company details for invoices are missing (accounts on account only).An account owner adds them under Settings. Nothing was sent.
4031406Trial account: only the trial message can be sent until the account is activated.Contact us to activate the account.
4291429Too many sign-ins from one address.Wait 15 minutes; reuse your token.
5001500Something went wrong on our side.Send the same call again (safe to retry).

Number formats

Phone numbers can be written as 0821234567, 27821234567 or +27821234567 — we normalise them for you. Each account sends to the numbers of one country.