Developer Integration Guide
Taifa Mobile SMS Gateway — REST API and SMPP integration reference.
Overview
The Taifa Mobile SMS Gateway is an SMS intermediary. You submit messages to the platform; the platform routes them to the correct mobile network operator in Kenya.
Web apps, scripts, low-to-medium volume
High-volume, telecom-grade throughput
Authentication
Every account has an API key (64-character hex string). Pass it in the
h_api_key HTTP header on every REST request.
h_api_key: YOUR_64_CHARACTER_API_KEY
Mobile Number Formats
All three formats are accepted and normalised to 254xxxxxxxxx internally.
| Format | Example |
|---|---|
| Local 07xx | 0702739804 |
| Local 01xx | 0102739804 |
| International | 254702739804 |
REST API Integration
The original PHP implementation. Fully supported. Existing integrations require no changes.
Base URL
https://api.taifamobile.co.ke/api/sms/
Request Headers
| Header | Required | Value |
|---|---|---|
h_api_key | Yes | Your API key |
Content-Type | Yes | application/json |
Request Body
{
"mobile": "0702739804",
"sender_name": "MYSENDER",
"message": "Hello from Taifa Mobile",
"response_type": "json",
"service_id": 0
}
Success Response
[
{
"status_code": "1000",
"status_desc": "Success",
"message_id": "10045",
"recipient_id": "50012",
"mobile_number": "254702739804",
"network_id": "1",
"message_cost": "1.00",
"credit_balance": "498.00"
}
]
Plain Text Response
Set "response_type": "plain" to receive:
1000;Success
cURL Example
curl -X POST https://api.taifamobile.co.ke/api/sms/sendsms.php \
-H "h_api_key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"mobile": "0702739804",
"sender_name": "MYSENDER",
"message": "Hello from Taifa Mobile",
"response_type": "json"
}'
PHP Example
<?php
$apiKey = 'YOUR_API_KEY';
$payload = json_encode([
'mobile' => '0702739804',
'sender_name' => 'MYSENDER',
'message' => 'Hello from Taifa Mobile',
'response_type' => 'json',
'service_id' => 0,
]);
$ch = curl_init('https://api.taifamobile.co.ke/api/sms/sendsms.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'h_api_key: ' . $apiKey,
'Content-Type: application/json',
],
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true)[0];
if ($result['status_code'] === '1000') {
echo "Sent! message_id = " . $result['message_id'];
} else {
echo "Error: " . $result['status_desc'];
}
curl https://api.taifamobile.co.ke/api/sms/units.php \
-H "h_api_key: YOUR_API_KEY"
{
"credit_balance": "498.00",
"date": "2026-04-03 07:13:38"
}
The v2 service runs alongside the PHP system. Response shapes are identical — existing integrations can switch by changing the base URL only.
Base URL
https://api.taifamobile.co.ke/v2/sms/
status_code field communicates success or failure
— identical to the PHP API.Request Headers
| Header | Required | Value |
|---|---|---|
h_api_key | Yes | Your API key |
Content-Type | Yes | application/json |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
mobile | string | Yes | Destination number |
sender_name | string | Yes | Registered sender ID |
message | string | Yes | Message text |
response_type | string | No | json (default) or plain |
service_id | string/int | No | Optional reference |
Success Response
[
{
"status_code": "1000",
"status_desc": "Success",
"message_id": "10045",
"recipient_id": "50012",
"mobile_number": "254702739804",
"network_id": "1",
"message_cost": "1.00",
"credit_balance": "498.00"
}
]
cURL Example
curl -X POST https://api.taifamobile.co.ke/v2/sms/sendsms \
-H "h_api_key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"mobile": "0702739804",
"sender_name": "MYSENDER",
"message": "Hello from Taifa Mobile"
}'
Python Example
import requests
resp = requests.post(
"https://api.taifamobile.co.ke/v2/sms/sendsms",
headers={"h_api_key": "YOUR_API_KEY"},
json={
"mobile": "0702739804",
"sender_name": "MYSENDER",
"message": "Hello from Taifa Mobile",
},
)
result = resp.json()[0]
if result["status_code"] == "1000":
print("Sent! message_id =", result["message_id"])
else:
print("Error:", result["status_desc"])
curl https://api.taifamobile.co.ke/v2/sms/units \
-H "h_api_key: YOUR_API_KEY"
{
"credit_balance": "498.00",
"date": "2026-04-03 07:13:38"
}
Register a short SMPP username (max 15 chars) and password (max 8 chars) before connecting on port 2775. The SMPP protocol has strict field length limits, so these are separate from your API key.
Request
curl -X POST https://api.taifamobile.co.ke/v2/sms/smpp-credentials \
-H "h_api_key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"smpp_username": "myuser",
"smpp_password": "myPass8c"
}'
Response
{
"smpp_username": "myuser",
"smpp_password": "myPass8c"
}
curl https://api.taifamobile.co.ke/v2/sms/health
{ "status": "ok", "queue_depth": 3 }
Status Codes
| status_code | Meaning | Action |
|---|---|---|
1000 | Success | — |
1001 | Invalid sender ID | Check sender_name is registered |
1003 | Invalid mobile number | Check number format and prefix |
1004 | Insufficient credit | Top up wallet |
1005 | DB error | Contact support |
1006 | Invalid API key | Check h_api_key header |
1009 | Invalid JSON body | Validate request body |
1011 | Account suspended | Contact support |
SMPP Integration
SMPP v3.4 is a persistent TCP protocol designed for high-volume SMS delivery. Once bound, a single connection can submit thousands of messages per second without the overhead of a new HTTP request per message.
| Property | Value |
|---|---|
| Protocol | SMPP v3.4 |
| Host | api.taifamobile.co.ke |
| Port | 2775 |
| Bind type | bind_transmitter |
| Idle timeout | 300 seconds |
POST /sms/smpp-credentials before connecting.Setup Steps
-
Set SMPP credentials
Use your REST API key to register a short username and password via the REST API.
curl -X POST https://api.taifamobile.co.ke/v2/sms/smpp-credentials \ -H "h_api_key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"smpp_username": "myuser", "smpp_password": "myPass8c"}'Save the response — use these as
system_idandpasswordat bind. -
Verify port connectivity
# Linux / Mac nc -zv api.taifamobile.co.ke 2775 # Windows PowerShell Test-NetConnection -ComputerName api.taifamobile.co.ke -Port 2775Expected:
Connection succeeded -
Connect and bind
Open a TCP connection to port 2775 and send a
bind_transmitterPDU.SMPP field Value system_idYour smpp_usernamepasswordYour smpp_passwordsystem_type(leave empty) interface_version0x34(SMPP v3.4)A successful bind returns
bind_transmitter_respwithcommand_status = 0x00000000. -
Submit messages
Send
submit_smPDUs. The server responds withsubmit_sm_respcontaining your internalmessage_idon success.Field Value source_addr_ton5alphanumeric /1numericsource_addr_npi0alphanumeric /1numericsource_addrRegistered sender ID e.g. MYSENDERdest_addr_ton1dest_addr_npi1destination_addrMobile in 254xxxxxxxxxformatdata_coding0GSM7/Latin |8UCS2/Unicode -
Keep the connection alive
Send an
enquire_linkPDU every 30–60 seconds. The server responds withenquire_link_resp. Connections idle for more than 300 seconds will be closed.
Python Example
pip install smpplib
Send a single message
import smpplib.client
import smpplib.consts
HOST = "api.taifamobile.co.ke"
PORT = 2775
USERNAME = "myuser" # smpp_username
PASSWORD = "myPass8c" # smpp_password
client = smpplib.client.Client(HOST, PORT)
client.connect()
client.bind_transmitter(system_id=USERNAME, password=PASSWORD)
pdu = client.send_message(
source_addr_ton = smpplib.consts.SMPP_TON_ALNUM,
source_addr_npi = smpplib.consts.SMPP_NPI_UNK,
source_addr = "MYSENDER",
dest_addr_ton = smpplib.consts.SMPP_TON_INTL,
dest_addr_npi = smpplib.consts.SMPP_NPI_ISDN,
destination_addr = "254702739804",
short_message = b"Hello from Taifa Mobile",
)
print("Sent — sequence:", pdu.sequence)
client.unbind()
client.disconnect()
Persistent connection with keep-alive
import smpplib.client
import smpplib.consts
import threading
import time
HOST = "api.taifamobile.co.ke"
PORT = 2775
USERNAME = "myuser"
PASSWORD = "myPass8c"
client = smpplib.client.Client(HOST, PORT)
client.connect()
client.bind_transmitter(system_id=USERNAME, password=PASSWORD)
def keep_alive():
while True:
time.sleep(30)
try:
client.enquire_link()
except Exception:
break
threading.Thread(target=keep_alive, daemon=True).start()
messages = [
("254702739804", "First message"),
("254725497524", "Second message"),
]
for mobile, text in messages:
pdu = client.send_message(
source_addr_ton = smpplib.consts.SMPP_TON_ALNUM,
source_addr_npi = smpplib.consts.SMPP_NPI_UNK,
source_addr = "MYSENDER",
dest_addr_ton = smpplib.consts.SMPP_TON_INTL,
dest_addr_npi = smpplib.consts.SMPP_NPI_ISDN,
destination_addr = mobile,
short_message = text.encode(),
)
print(f"Queued {mobile} — seq {pdu.sequence}")
client.unbind()
client.disconnect()
PHP Example
composer require onlinecity/php-smpp
<?php
require 'vendor/autoload.php';
use SMPP\Client\SmppClient;
use SMPP\Transport\SocketTransport;
$transport = new SocketTransport(['api.taifamobile.co.ke'], 2775);
$transport->setRecvTimeout(10000);
$smpp = new SmppClient($transport);
$transport->open();
$smpp->bindTransmitter("myuser", "myPass8c");
$from = new SMPP\SMPP\Address("MYSENDER", SMPP\SMPP\SMPP::TON_ALPHANUMERIC);
$to = new SMPP\SMPP\Address("254702739804", SMPP\SMPP\SMPP::TON_INTERNATIONAL, SMPP\SMPP\SMPP::NPI_E164);
$msgid = $smpp->sendSMS($from, $to, "Hello from Taifa Mobile");
echo "Sent! message_id = $msgid\n";
$smpp->close();
$smpp connection and call
sendSMS() in a loop rather than reconnecting per message.SMPP Error Codes
Bind errors
| command_status | Name | Cause |
|---|---|---|
0x00000000 | ESME_ROK | Bind accepted |
0x0000000D | ESME_RBINDFAIL | Wrong credentials or account inactive |
0x00000004 | ESME_RINVBNDSTS | Already bound |
Submit errors
| command_status | Name | Cause |
|---|---|---|
0x00000000 | ESME_ROK | Message accepted |
0x00000045 | ESME_RSUBMITFAIL | Rejected — see reasons below |
0x00000008 | ESME_RSYSERR | Internal server error |
0x00000004 | ESME_RINVBNDSTS | submit_sm sent before bind |
ESME_RSUBMITFAIL — rejection reasons
| VAS code | Reason | Fix |
|---|---|---|
1001 | Invalid sender ID | Check source_addr is registered |
1003 | Invalid destination | Use 254xxxxxxxxx format |
1004 | Insufficient credit | Top up wallet |
1011 | Account suspended | Contact support |
Best Practices
| Practice | Why |
|---|---|
| Reuse a single persistent connection | Avoids bind/unbind overhead. One connection handles thousands of messages per second. |
Send enquire_link every 30–60 s |
Prevents idle timeout (300 s) and detects dead connections early. |
Handle ESME_RSUBMITFAIL per message |
One rejection should not break the send loop — log it and continue. |
Use data_coding = 0 for Latin/GSM text |
GSM7 packs 160 chars per SMS part. Use 8 (UCS2) only for non-Latin scripts. |
Destination in 254xxxxxxxxx format |
All Kenyan numbers must be in E.164 international format. |
| Implement reconnect logic | TCP connections can drop. Catch exceptions, reconnect, re-bind, and resume. |