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.

REST API
HTTP/HTTPS — base path /v2/
Web apps, scripts, low-to-medium volume
SMPP v3.4
Persistent TCP — port 2775
High-volume, telecom-grade throughput
Both paths share the same account, sender IDs, and wallet balance. You can use both simultaneously.

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
Keep your API key secret. Do not expose it in client-side JavaScript or public repositories.

Mobile Number Formats

All three formats are accepted and normalised to 254xxxxxxxxx internally.

FormatExample
Local 07xx0702739804
Local 01xx0102739804
International254702739804

REST API Integration

Legacy PHP-based endpoint — still active, no changes required

The original PHP implementation. Fully supported. Existing integrations require no changes.

Base URL

https://api.taifamobile.co.ke/api/sms/

POST /api/sms/sendsms.php

Request Headers

HeaderRequiredValue
h_api_keyYesYour API key
Content-TypeYesapplication/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'];
}

GET /api/sms/units.php
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"
}
v2 Python-based — same response shape, extra endpoints

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/
All responses are HTTP 200. The status_code field communicates success or failure — identical to the PHP API.

POST /sms/sendsms

Request Headers

HeaderRequiredValue
h_api_keyYesYour API key
Content-TypeYesapplication/json

Request Body

FieldTypeRequiredDescription
mobilestringYesDestination number
sender_namestringYesRegistered sender ID
messagestringYesMessage text
response_typestringNojson (default) or plain
service_idstring/intNoOptional 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"])

GET /sms/units
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"
}

POST /sms/smpp-credentials v2 only

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"
}
Calling this endpoint again overwrites the previous password. Active SMPP sessions will need to re-bind with the new credentials.

GET /sms/health v2 only
curl https://api.taifamobile.co.ke/v2/sms/health
{ "status": "ok", "queue_depth": 3 }

Status Codes

status_codeMeaningAction
1000Success
1001Invalid sender IDCheck sender_name is registered
1003Invalid mobile numberCheck number format and prefix
1004Insufficient creditTop up wallet
1005DB errorContact support
1006Invalid API keyCheck h_api_key header
1009Invalid JSON bodyValidate request body
1011Account suspendedContact 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.

PropertyValue
ProtocolSMPP v3.4
Hostapi.taifamobile.co.ke
Port2775
Bind typebind_transmitter
Idle timeout300 seconds
SMPP credentials are separate from your REST API key. Set them once using POST /sms/smpp-credentials before connecting.

Setup Steps

  1. 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_id and password at bind.

  2. Verify port connectivity

    # Linux / Mac
    nc -zv api.taifamobile.co.ke 2775
    
    # Windows PowerShell
    Test-NetConnection -ComputerName api.taifamobile.co.ke -Port 2775

    Expected: Connection succeeded

  3. Connect and bind

    Open a TCP connection to port 2775 and send a bind_transmitter PDU.

    SMPP fieldValue
    system_idYour smpp_username
    passwordYour smpp_password
    system_type(leave empty)
    interface_version0x34 (SMPP v3.4)

    A successful bind returns bind_transmitter_resp with command_status = 0x00000000.

  4. Submit messages

    Send submit_sm PDUs. The server responds with submit_sm_resp containing your internal message_id on success.

    FieldValue
    source_addr_ton5 alphanumeric / 1 numeric
    source_addr_npi0 alphanumeric / 1 numeric
    source_addrRegistered sender ID e.g. MYSENDER
    dest_addr_ton1
    dest_addr_npi1
    destination_addrMobile in 254xxxxxxxxx format
    data_coding0 GSM7/Latin  |  8 UCS2/Unicode
  5. Keep the connection alive

    Send an enquire_link PDU every 30–60 seconds. The server responds with enquire_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();
For high volume, reuse the same $smpp connection and call sendSMS() in a loop rather than reconnecting per message.

SMPP Error Codes

Bind errors

command_statusNameCause
0x00000000ESME_ROKBind accepted
0x0000000DESME_RBINDFAILWrong credentials or account inactive
0x00000004ESME_RINVBNDSTSAlready bound

Submit errors

command_statusNameCause
0x00000000ESME_ROKMessage accepted
0x00000045ESME_RSUBMITFAILRejected — see reasons below
0x00000008ESME_RSYSERRInternal server error
0x00000004ESME_RINVBNDSTSsubmit_sm sent before bind

ESME_RSUBMITFAIL — rejection reasons

VAS codeReasonFix
1001Invalid sender IDCheck source_addr is registered
1003Invalid destinationUse 254xxxxxxxxx format
1004Insufficient creditTop up wallet
1011Account suspendedContact support

Best Practices

PracticeWhy
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.