Get started with M-Pesa integration in minutes using our comprehensive code examples and step-by-step guide.

Complete examples in PHP, Node.js, and cURL for quick integration.

Getting Started

  1. 1. Get Your Credentials

    Register for an account and onboard your shortcode to get API credentials.

    Steps:
    1. Register at https://felixdev.io/register
    2. Complete account setup
    3. Add your shortcode in dashboard
    4. Copy API key and tracking code
    5. Start integrating!
  2. 2. Test Your Integration

    Start with small test amounts to verify your integration works correctly.

    Testing Tips:
    • Use small amounts (KES 1-10)
    • Test with your own phone number
    • Verify webhook delivery
    • Check transaction status
    • Test error scenarios
  3. View Examples

PHP Example

  1. Complete PHP Integration

    Full PHP example for initiating payments and handling webhooks.

    PHP
    <?php
    // Initiate M-Pesa Payment
    function initiatePayment($apiKey, $trackingCode, $msisdn, $amount, $callbackUrl) {
        $data = [
            'msisdn' => $msisdn,
            'amount' => $amount,
            'callback' => $callbackUrl
        ];
    
        $headers = [
            'Content-Type: application/json',
            'apikey: ' . $apiKey,
            'linkid: ' . $trackingCode
        ];
    
        $ch = curl_init('https://felixdev.io/api/v1/initiate');
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
    
        $result = json_decode($response, true);
    
        if ($httpCode === 200 && $result['success']) {
            return [
                'success' => true,
                'request_id' => $result['request_id'],
                'message' => 'Payment initiated successfully'
            ];
        } else {
            return [
                'success' => false,
                'error' => $result['error'] ?? 'Unknown error',
                'message' => $result['message'] ?? 'Payment failed'
            ];
        }
    }
    
    // Handle Webhook Callback
    function handleWebhook() {
        $rawPayload = file_get_contents('php://input');
        $headers = getallheaders();
        $payload = json_decode($rawPayload, true);
    
        // Verify signature
        $signature = $headers['X-Signature'] ?? '';
        $apiKey = $headers['X-API-Key'] ?? '';
        $linkId = $headers['X-Link-ID'] ?? '';
        
        // Generate expected signature
        $secretKey = 'your_app_key' . $linkId;
        $expectedSignature = hash_hmac('sha256', $rawPayload, $secretKey);
    
        if (hash_equals($signature, $expectedSignature)) {
            // Webhook is authentic
            if ($payload['status'] === 'completed') {
                // Payment successful
                $receiptNumber = $payload['mpesa_receipt_number'];
                $amount = $payload['amount'];
                $phone = $payload['msisdn'];
                
                // Update your database
                updatePaymentStatus($payload['request_id'], 'completed', $receiptNumber);
                
                // Send confirmation
                sendPaymentConfirmation($phone, $amount, $receiptNumber);
            } else {
                // Payment failed/cancelled
                updatePaymentStatus($payload['request_id'], $payload['status']);
            }
            
            // Always return 200 OK
            http_response_code(200);
            echo json_encode(['status' => 'received']);
        } else {
            // Invalid signature
            http_response_code(401);
            echo json_encode(['error' => 'Invalid signature']);
        }
    }
    
    // Example usage
    $result = initiatePayment(
        'pk_your_api_key_here',
        'sc_your_tracking_code_here',
        '254712345678',
        100,
        'https://yoursite.com/webhook'
    );
    
    if ($result['success']) {
        echo "Payment initiated: " . $result['request_id'];
    } else {
        echo "Error: " . $result['error'];
    }
    ?>
  2. Node.js Example

Node.js Example

  1. Node.js Integration

    Complete Node.js example using axios for API integration.

    JavaScript
    const axios = require('axios');
    const crypto = require('crypto');
    
    // Initiate M-Pesa Payment
    async function initiatePayment(apiKey, trackingCode, msisdn, amount, callbackUrl) {
      try {
        const response = await axios.post('https://felixdev.io/api/v1/initiate', {
          msisdn: msisdn,
          amount: amount,
          callback: callbackUrl
        }, {
          headers: {
            'Content-Type': 'application/json',
            'apikey': apiKey,
            'linkid': trackingCode
          },
          timeout: 60000
        });
        
        if (response.data.success) {
          return {
            success: true,
            request_id: response.data.request_id,
            message: 'Payment initiated successfully'
          };
        } else {
          return {
            success: false,
            error: response.data.error,
            message: response.data.message
          };
        }
      } catch (error) {
        return {
          success: false,
          error: 'NETWORK_ERROR',
          message: error.response?.data?.message || error.message
        };
      }
    }
    
    // Handle Webhook (Express.js)
    const express = require('express');
    const app = express();
    
    app.use(express.json());
    
    app.post('/webhook', (req, res) => {
      const signature = req.headers['x-signature'];
      const apiKey = req.headers['x-api-key'];
      const linkId = req.headers['x-link-id'];
      const payload = JSON.stringify(req.body);
      
      // Verify signature
      const secretKey = 'your_app_key' + linkId;
      const expectedSignature = crypto.createHmac('sha256', secretKey)
                                      .update(payload)
                                      .digest('hex');
      
      if (signature === expectedSignature) {
        // Webhook is authentic
        if (req.body.status === 'completed') {
          // Payment successful
          updatePaymentStatus(req.body.request_id, 'completed', req.body.mpesa_receipt_number);
          sendPaymentConfirmation(req.body.msisdn, req.body.amount, req.body.mpesa_receipt_number);
        } else {
          // Payment failed/cancelled
          updatePaymentStatus(req.body.request_id, req.body.status);
        }
        
        res.status(200).json({ status: 'received' });
      } else {
        res.status(401).json({ error: 'Invalid signature' });
      }
    });
    
    // Example usage
    async function testPayment() {
      const result = await initiatePayment(
        'pk_your_api_key_here',
        'sc_your_tracking_code_here',
        '254712345678',
        100,
        'https://yoursite.com/webhook'
      );
      
      if (result.success) {
        console.log('Payment initiated:', result.request_id);
      } else {
        console.error('Error:', result.error);
      }
    }
    
    testPayment();
  2. cURL Example

cURL Examples

  1. Basic Payment Request

    Simple cURL command for testing payment initiation.

    Bash
    curl -X POST https://felixdev.io/api/v1/initiate \
      -H "Content-Type: application/json" \
      -H "apikey: pk_your_api_key_here" \
      -H "linkid: sc_your_tracking_code_here" \
      -d '{
        "msisdn": "254712345678",
        "amount": 100,
        "callback": "https://yoursite.com/webhook"
      }'
  2. Check Transaction Status

    Query transaction status using the request ID.

    Bash
    curl -X GET https://felixdev.io/api/v1/status/REQ_abc123def456 \
      -H "apikey: pk_your_api_key_here" \
      -H "linkid: sc_your_tracking_code_here"
  3. Webhook Testing

    Test your webhook endpoint with curl to ensure it handles POST requests correctly.

    Bash
    # Test your webhook endpoint
    curl -X POST https://yoursite.com/webhook \
      -H "Content-Type: application/json" \
      -H "X-API-Key: pk_your_api_key_here" \
      -H "X-Link-ID: sc_your_tracking_code_here" \
      -H "X-Signature: test_signature" \
      -d '{
        "request_id": "TEST_123",
        "status": "completed",
        "amount": 100,
        "msisdn": "254712345678",
        "mpesa_receipt_number": "TEST_RECEIPT",
        "result_code": "0",
        "result_desc": "Test webhook"
      }'
  4. Best Practices