Codian Payments
API Platform

Integrate M-Pesa payments in minutes. STK Push, callbacks, and webhooks made simple. Secure, scalable, and developer-friendly.

// Initiate STK Push - Custom Integration
$payload = [
    "client_id" => "codian_prd_xxxxxxxxxxxx", // Your client ID
    "client_secret" => "codian_sk_prd_xxxxxxxxxxxxxxxxxxxxxxxxxxxx", // Your secret
    "amount" => 100.00,
    "phone" => "2547xxxxxx" // Customer phone number
];

$ch = curl_init('https://api.codian.co.ke/v1/payments/c2b/initiate/');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);

if ($data['success']) {
    // Store checkout ID to match with webhook callback
    $checkout_id = $data['CheckoutRequestID'];
    echo "STK Push sent. Checkout ID: " . $checkout_id;
    // Wait for webhook confirmation
}
// Initiate STK Push with Fetch API
const paymentData = {
    client_id: 'codian_prd_xxxxxxxxxxxx', // Your client ID
    client_secret: 'codian_sk_prd_xxxxxxxxxxxxxxxxxxxxxxxxxxxx', // Your secret
    amount: 100.00,
    phone: '2547xxxxxx' // Customer phone number
};

fetch('https://api.codian.co.ke/v1/payments/c2b/initiate/', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(paymentData)
})
.then(res => res.json())
.then(data => {
    if (data.success) {
        console.log('STK Push sent. Checkout ID:', data.CheckoutRequestID);
        // Show prompt to user
        alert('Please check your phone and enter PIN to complete payment');
        
        // Store checkout ID to match with webhook
        localStorage.setItem('checkout_id', data.CheckoutRequestID);
    }
})
.catch(error => console.error('Payment failed:', error));
import requests

# Initiate STK Push
payload = {
    "client_id": "codian_prd_xxxxxxxxxxxx",  # Your client ID
    "client_secret": "codian_sk_prd_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",  # Your secret
    "amount": 100.00,
    "phone": "2547xxxxxx"  # Customer phone number
}

response = requests.post(
    "https://api.codian.co.ke/v1/payments/c2b/initiate/",
    json=payload,
    headers={"Content-Type": "application/json"},
    timeout=30
)

data = response.json()
if data.get("success"):
    checkout_id = data['CheckoutRequestID']
    print(f"STK Push initiated! Checkout ID: {checkout_id}")
    print("Waiting for webhook callback...")
    # Store checkout_id in database to match with callback
else:
    print(f"Error: {data.get('error', 'Unknown error')}")
const axios = require('axios');

// Initiate STK Push
const paymentData = {
    client_id: 'codian_prd_xxxxxxxxxxxx', // Your client ID
    client_secret: 'codian_sk_prd_xxxxxxxxxxxxxxxxxxxxxxxxxxxx', // Your secret
    amount: 100.00,
    phone: '2547xxxxxx' // Customer phone number
};

async function initiatePayment() {
    try {
        const response = await axios.post(
            'https://api.codian.co.ke/v1/payments/c2b/initiate/',
            paymentData,
            { headers: { 'Content-Type': 'application/json' } }
        );
        
        if (response.data.success) {
            console.log('STK Push sent. Checkout ID:', response.data.CheckoutRequestID);
            // Store checkout ID for webhook matching
            return response.data.CheckoutRequestID;
        }
    } catch (error) {
        console.error('Payment initiation failed:', error.response?.data || error.message);
    }
}

initiatePayment();
// callback.php - Webhook endpoint (must return HTTP 200)
$raw_data = file_get_contents('php://input');
$callback = json_decode($raw_data, true);

if (isset($callback['Body']['stkCallback'])) {
    $stk = $callback['Body']['stkCallback'];
    $checkout_id = $stk['CheckoutRequestID'];
    $result_code = $stk['ResultCode'];
    $result_desc = $stk['ResultDesc'];
    
    // Log the callback for debugging
    error_log("Callback received - CheckoutID: $checkout_id, ResultCode: $result_code");
    
    if ($result_code == 0) {
        // Success - extract metadata
        $metadata = [];
        foreach ($stk['CallbackMetadata']['Item'] as $item) {
            $metadata[$item['Name']] = $item['Value'];
        }
        
        $receipt = $metadata['MpesaReceiptNumber']; // M-Pesa transaction ID
        $amount = $metadata['Amount'];
        $phone = $metadata['PhoneNumber'];
        
        // Update database: set status to completed
        // UPDATE payments SET status='completed', receipt='$receipt' 
        // WHERE checkout_id='$checkout_id'
        
        http_response_code(200);
        echo json_encode(['success' => true, 'message' => 'Callback processed']);
    } else {
        // Payment failed - handle accordingly
        // UPDATE payments SET status='failed', result_desc='$result_desc' 
        // WHERE checkout_id='$checkout_id'
        
        http_response_code(200); // Always return 200
        echo json_encode(['success' => false, 'message' => $result_desc]);
    }
} else {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'Invalid callback']);
}
{
    "Body": {
        "stkCallback": {
            "MerchantRequestID": "xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "CheckoutRequestID": "ws_xx_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "ResultCode": 0,
            "ResultDesc": "The service request is processed successfully.",
            "CallbackMetadata": {
                "Item": [
                    {
                        "Name": "Amount",
                        "Value": 100
                    },
                    {
                        "Name": "MpesaReceiptNumber",
                        "Value": "xxxxxxx"  // M-Pesa transaction ID
                    },
                    {
                        "Name": "TransactionDate",
                        "Value": "2025-01-23 14:30:26"
                    },
                    {
                        "Name": "PhoneNumber",
                        "Value": 2547xxxxxx  // Customer phone
                    }
                ]
            }
        }
    }
}

// Result Codes:
// 0: Success
// 1032: Transaction failed - insufficient funds
// 1037: Transaction cancelled by user
// 1: Internal server error