UnifiedPay API Documentation

Integrate M-Pesa payments with a few lines of code. Free forever.

🚀 Quick Start

  1. Sign up for a free account (no activation required)
  2. Log in to your dashboard and link a Paybill, Till, or Bank Account
  3. Copy your generated consumer_key and consumer_secret
  4. Use the endpoints below to validate, send STK push, and check transaction status

Base URL

https://unifiedpay.co.ke

All requests must be HTTPS POST.

POST Validate Credentials

/auth/cred/{consumer_key}/{consumer_secret}/url

Check if your API credentials are valid and active.

Request

No request body required.

Response

Success (200)
{
  "ResultCode": 0,
  "message": "Credentials valid",
  "shortcode": "4201775"
}
Error (401)
{
  "ResultCode": 401,
  "errorMessage": "Invalid API credentials"
}
curl -X POST https://unifiedpay.co.ke/auth/cred/YOUR_CONSUMER_KEY/YOUR_CONSUMER_SECRET/url
<?php
$url = 'https://unifiedpay.co.ke/auth/cred/YOUR_CONSUMER_KEY/YOUR_CONSUMER_SECRET/url';

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
if ($result['ResultCode'] == 0) {
    echo "Credentials valid. Shortcode: " . $result['shortcode'];
} else {
    echo "Error: " . $result['errorMessage'];
}
?>
import requests

url = "https://unifiedpay.co.ke/auth/cred/YOUR_CONSUMER_KEY/YOUR_CONSUMER_SECRET/url"
response = requests.post(url)
data = response.json()

if data['ResultCode'] == 0:
    print(f"Valid. Shortcode: {data['shortcode']}")
else:
    print(f"Error: {data['errorMessage']}")
fetch('https://unifiedpay.co.ke/auth/cred/YOUR_CONSUMER_KEY/YOUR_CONSUMER_SECRET/url', {
    method: 'POST'
})
.then(res => res.json())
.then(data => {
    if (data.ResultCode === 0) {
        console.log('Valid. Shortcode:', data.shortcode);
    } else {
        console.error('Error:', data.errorMessage);
    }
});

POST Send STK Push

/auth/cred/{consumer_key}/{consumer_secret}/sendstk

Initiate M-Pesa payment prompt on customer's phone.

Request Body (JSON)

FieldTypeRequiredDescription
amountintegerYesAmount to pay (KES, whole numbers only)
msisdnstringYesCustomer phone number (e.g., 254712345678 or 0712345678)
referencestringYesPayment reference/description (max 20 chars)
account_numberstringNoAccount number for Paybill (optional)

Response

Success (200)
{
  "ResponseCode": "0",
  "success": true,
  "message": "STK push initiated",
  "transaction_request_id": "FL20240315143022123",
  "MerchantRequestID": "2d5c-4e7b-8f1a-9c3d6e8f1a2b",
  "CheckoutRequestID": "ws_CO_1234567890"
}
Error (400/500)
{
  "ResultCode": 400,
  "errorMessage": "Missing required fields"
}
curl -X POST https://unifiedpay.co.ke/auth/cred/YOUR_KEY/YOUR_SECRET/sendstk \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "1",
    "msisdn": "254712345678",
    "reference": "Test Payment",
    "account_number": "INV001"
  }'
<?php
$url = 'https://unifiedpay.co.ke/auth/cred/YOUR_KEY/YOUR_SECRET/sendstk';
$data = [
    'amount' => 1,
    'msisdn' => '254712345678',
    'reference' => 'Test Payment',
    'account_number' => 'INV001'
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
if ($result['ResponseCode'] == '0') {
    echo "STK sent. Transaction ID: " . $result['transaction_request_id'];
} else {
    echo "Error: " . ($result['errorMessage'] ?? 'Unknown error');
}
?>
import requests
import json

url = "https://unifiedpay.co.ke/auth/cred/YOUR_KEY/YOUR_SECRET/sendstk"
payload = {
    "amount": 1,
    "msisdn": "254712345678",
    "reference": "Test Payment",
    "account_number": "INV001"
}
headers = {"Content-Type": "application/json"}

response = requests.post(url, json=payload, headers=headers)
data = response.json()

if data.get('ResponseCode') == '0':
    print(f"STK sent. Transaction ID: {data['transaction_request_id']}")
else:
    print(f"Error: {data.get('errorMessage')}")
fetch('https://unifiedpay.co.ke/auth/cred/YOUR_KEY/YOUR_SECRET/sendstk', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        amount: 1,
        msisdn: '254712345678',
        reference: 'Test Payment',
        account_number: 'INV001'
    })
})
.then(res => res.json())
.then(data => {
    if (data.ResponseCode === '0') {
        console.log('STK sent. ID:', data.transaction_request_id);
    } else {
        console.error('Error:', data.errorMessage);
    }
});

POST Transaction Status

/auth/cred/{consumer_key}/{consumer_secret}/sendstatus

Query the status of a previously initiated STK push transaction.

Request Body (JSON)

FieldTypeRequiredDescription
transaction_request_idstringYesThe ID returned from the /sendstk endpoint

Response

Success (200)
{
  "ResultCode": "200",
  "ResultDesc": "Success",
  "CheckoutRequestID": "ws_CO_1234567890",
  "MerchantRequestID": "2d5c-4e7b-8f1a-9c3d6e8f1a2b",
  "TransactionStatus": "Completed",
  "TransactionCode": "0",
  "TransactionReceipt": "QKJ8H7G9L2",
  "TransactionAmount": "1",
  "Msisdn": "254712345678",
  "TransactionDate": "20240315143022",
  "TransactionReference": "Test Payment"
}
Pending
{
  "ResultCode": "200",
  "ResultDesc": "Transaction is pending",
  "TransactionStatus": "Pending",
  ...
}
curl -X POST https://unifiedpay.co.ke/auth/cred/YOUR_KEY/YOUR_SECRET/sendstatus \
  -H "Content-Type: application/json" \
  -d '{"transaction_request_id": "FL20240315143022123"}'
<?php
$url = 'https://unifiedpay.co.ke/auth/cred/YOUR_KEY/YOUR_SECRET/sendstatus';
$data = ['transaction_request_id' => 'FL20240315143022123'];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
echo "Status: " . $result['TransactionStatus'];
if ($result['TransactionStatus'] == 'Completed') {
    echo " Receipt: " . $result['TransactionReceipt'];
}
?>
import requests

url = "https://unifiedpay.co.ke/auth/cred/YOUR_KEY/YOUR_SECRET/sendstatus"
payload = {"transaction_request_id": "FL20240315143022123"}
headers = {"Content-Type": "application/json"}

response = requests.post(url, json=payload, headers=headers)
data = response.json()

print(f"Status: {data['TransactionStatus']}")
if data['TransactionStatus'] == 'Completed':
    print(f"Receipt: {data['TransactionReceipt']}")
fetch('https://unifiedpay.co.ke/auth/cred/YOUR_KEY/YOUR_SECRET/sendstatus', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ transaction_request_id: 'FL20240315143022123' })
})
.then(res => res.json())
.then(data => {
    console.log('Status:', data.TransactionStatus);
    if (data.TransactionStatus === 'Completed') {
        console.log('Receipt:', data.TransactionReceipt);
    }
});

Error Codes Reference

0 - Success
1 - Insufficient balance
1032 - Cancelled by user
1037 - Timeout (user unreachable)
2001 - Invalid initiator info
1019 - Invalid receiving organization
401 - Invalid API credentials
400 - Missing required fields
404 - Transaction not found
500 - Server error
💡 Note: The callback URL is automatically handled by UnifiedPay. You can optionally set a webhook URL in your dashboard to receive real-time payment notifications.