Internal Services

Bulk SMS Gateway API

Send transactional SMS, OTP alerts, and campaign messages in Kenya with the Statum Bulk SMS API. See sender ID, request, and delivery details.

The Bulk SMS Gateway API gives applications a single way to send transactional alerts, OTPs, and campaign messages. The service supports delivery to Safaricom, Airtel, and Telkom numbers and provides delivery information after the message is handed to the carrier.

Send messages through the documented REST endpoint. Requests require authentication and should be made over HTTPS from your server.

POST
https://api.statum.co.ke/api/v2/sms

SMS Gateway API Features

The SMS service includes the following features:

High-Speed Throughput

Use the API for application messages such as one-time passwords and account alerts.

Delivery reports

Register a callback URL to receive delivery reports from the supported carrier networks.

Full Unicode Support

Send Unicode content, including Kiswahili text, special characters, and emoji, subject to the character limits below.

Secure Authentication

Authenticate requests with HTTP Basic Authentication and keep the credentials in server-side configuration.

Sender ID Registration in Kenya

A custom-branded Sender ID must be registered before it can be used for messages. The checklist below shows the documents and steps used for the submission to the mobile operators.

Required Support Documents

Prepare the following documents before sending the request. The operators use them to verify the business and the requested Sender ID:

  • A signed and stamped Authorization Letter.
  • A valid PDF of your Business Registration Certificate, Certificate of Incorporation, or Trade Mark Registration.

Authorization Letter Template

Download the template letter, add your company details on letterhead, sign and stamp it, then send it to for processing.

Download Template (.docx)

Registration Timeline

Allow approximately 2 to 3 business days for processing across Safaricom, Airtel, and Telkom.

Setup Cost

Custom Sender Name registration costs KES 10,000 per Mobile Operator (Telco).

SMS Character Limits & Concatenation

Message length affects how an SMS is divided and billed. The relevant limits are:

  • Single SMS: Up to 160 characters when standard 7-bit GSM encoding is used.
  • Concatenated SMS: Longer messages are split and reassembled on the recipient's phone. Each part can contain up to 153 characters because of the concatenation header.
  • Unicode encoding: Messages containing characters outside the GSM set use UCS-2 and are limited to 70 characters per part.

SMS API Request Parameters

Send a POST request with a JSON body containing the following parameters:

Parameter Type Required Description Example
phone_number String Yes Recipient phone number in international format without the leading plus sign. 254721553678
message String Yes The message body text to deliver. Keep within GSM character standards. Your verification code is 8847.
sender_id String Yes The registered custom Sender ID or short code. Statum

Request Implementation Example

Send Bulk SMS
curl -X POST https://api.statum.co.ke/api/v2/sms \
  -H "Authorization: Basic MmJlOTg5ZD...==" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "254721553678",
    "sender_id": "Statum",
    "message": "This is a test message through our API."
  }'
$consumerKey = "YOUR_CONSUMER_KEY";
$consumerSecret = "YOUR_CONSUMER_SECRET";
$auth = base64_encode($consumerKey . ":" . $consumerSecret);

$client = new \GuzzleHttp\Client();
$response = $client->post('https://api.statum.co.ke/api/v2/sms', [
    'headers' => [
        'Authorization' => 'Basic ' . $auth,
        'Content-Type'  => 'application/json'
    ],
    'json' => [
        'phone_number' => '254721553678',
        'sender_id'    => 'Statum',
        'message'      => 'This is a test message through our API.'
    ]
]);

$result = json_decode($response->getBody()->getContents(), true);
const axios = require('axios');
const auth = Buffer.from('YOUR_CONSUMER_KEY:YOUR_CONSUMER_SECRET').toString('base64');

axios.post('https://api.statum.co.ke/api/v2/sms', {
    phone_number: '254721553678',
    sender_id: 'Statum',
    message: 'This is a test message through our API.'
}, {
    headers: {
        'Authorization': `Basic ${auth}`,
        'Content-Type': 'application/json'
    }
})
.then(response => console.log(response.data))
.catch(error => console.error(error));

SMS Gateway API Response Format

The gateway returns a synchronous JSON response after receiving the POST request. This response tells you how the request was accepted or rejected:

Parameter Type Description Example
status_code Number Standard response code (200 = Success, 401 = Unauthorized, etc.) 200
description String Human-readable response message. Operation successful.
request_id String A unique UUID transaction ID used to map webhook callbacks. 9b11ac7b-08bf-4cb1-96ca-eb5f8805985f

Sample Response Payload

Success Response
{
    "status_code": 200,
    "description": "Operation successful.",
    "request_id": "9b11ac7b-08bf-4cb1-96ca-eb5f8805985f"
}

Delivery Reports & Webhook Setup

After the message is queued, the carrier processes it separately. Register a callback URL if you want the final delivery report as an asynchronous HTTP POST webhook:

Parameter Type Description Example
request_id String The reference ID returned from the initial POST request. 9b11ac7b-08bf-4cb1-96ca-eb5f8805985f
charge Decimal The actual financial charge deducted from your wallet for this SMS. 50
account_balance Decimal Your available wallet balance after the charge deduction. 950.25
result_code Number Status code representing transaction outcome (200 = Delivered). 200
result_desc String The description detailing status (e.g. Delivered, Rejected, Failed). Successfully delivered

Sample Webhook Payload

The delivery state is updated asynchronously after the message reaches the carrier. Statum sends a POST request with the JSON payload to your callback URL. Use the request_id to associate it with the original request and read the final carrier code.

Callback Notification
{
    "request_id": "9b11ac7b-08bf-4cb1-96ca-eb5f8805985f",
    "charge": 50,
    "account_balance": 950.25,
    "result_code": 200,
    "result_desc": "Successfully delivered"
}

Sample Callback Handler Implementation

Configure a server endpoint that accepts POST requests with Content-Type: application/json. Read the payload, update your message record, and return HTTP 200 OK within 3 seconds after handling it.

PHP Callback Handler
<?php
// Route target: https://yourdomain.com/api/sms/callback
$input = file_get_contents('php://input');
$payload = json_decode($input, true);

if (!$payload) {
    http_response_code(400);
    exit();
}

$requestId = $payload['request_id'];
$resultCode = $payload['result_code'];

if ($resultCode === 200) {
    // SMS was successfully delivered to the device. Update database order/alert status.
    updateSmsStatus($requestId, 'delivered');
} else {
    // Delivery failed (e.g., number out of service, subscriber absent, etc.)
    updateSmsStatus($requestId, 'failed', $payload['result_desc']);
}

// Return 200 to acknowledge receipt of webhook
http_response_code(200);
echo json_encode(['status' => 'acknowledged']);
?>