Webhooks

When you provide a callback_url on a payment request, SwiftWallet POSTs the transaction result to that URL after M-Pesa processes it. The payload structure varies by transaction type as shown below.

Callback Types

Stk callback

Sent when an STK Push payment is completed or fails. Includes M-Pesa result data and optional channel info.

POST application/json
{
    "success": true,
    "transaction_id": 789,
    "external_reference": "INV-12345",
    "checkout_request_id": "ws_CO_12345...",
    "merchant_request_id": "12345-67890",
    "status": "completed",
    "timestamp": "2024-12-31T12:30:05+03:00",
    "service_fee": 5,
    "result": {
        "ResultCode": 0,
        "ResultDesc": "Success",
        "Amount": 100,
        "MpesaReceiptNumber": "ABC123XYZ",
        "Phone": "254712345678",
        "TransactionDate": "20241231123000"
    },
    "channel_info": {
        "channel_type": "paybill",
        "channel_name": "Main Paybill",
        "routing_description": "Paybill 174379, Account: ACC001"
    }
}

B2c callback

Sent when a B2C payment is completed or fails. Internal M-Pesa balance snapshots (Utility/Working/ChargesPaid account balances) are never included — use the Wallet API to check your own balance.

POST application/json
{
    "success": true,
    "transaction_id": 790,
    "external_reference": "SALARY-DEC-001",
    "originatorConversationID": "12345-67890-1",
    "conversationID": "AG_20241231_...",
    "transactionID": "NLJ41HAY6Q",
    "status": "completed",
    "timestamp": "2024-12-31T12:35:00+03:00",
    "service_fee": 15,
    "withdrawal_fee": 15,
    "result": {
        "ResultCode": 0,
        "ResultDesc": "The service request is processed successfully.",
        "TransactionAmount": 1000,
        "TransactionReceipt": "NLJ41HAY6Q",
        "RecipientIsRegistered": "Y",
        "TransactionCompletedDateTime": "31.12.2024 12:35:00",
        "ReceiverPublicName": "254712345678 - John Doe"
    },
    "transaction_info": {
        "phone_number": "254712345678",
        "amount": 1000,
        "currency": "KES",
        "transaction_type": "B2C"
    },
    "payer_name": "Jane Merchant"
}

B2pochi callback

Sent when a B2Pochi payment is completed or fails. Same structure as B2C callback with transaction_type set to B2Pochi. Internal M-Pesa balance snapshots are excluded.

POST application/json
{
    "success": true,
    "transaction_id": 795,
    "external_reference": "POCHI-PAY-001",
    "originatorConversationID": "12345-67890-1",
    "conversationID": "AG_20241231_...",
    "transactionID": "SG632NMUAB",
    "status": "completed",
    "timestamp": "2024-12-31T12:30:00+03:00",
    "service_fee": 15,
    "withdrawal_fee": 15,
    "result": {
        "ResultCode": 0,
        "ResultDesc": "The service request is processed successfully.",
        "TransactionAmount": 1000,
        "TransactionReceipt": "SG632NMUAB",
        "RecipientIsRegistered": "Y",
        "TransactionCompletedDateTime": "31.12.2024 12:30:00",
        "ReceiverPublicName": "254705912645 - JOHN DOE"
    },
    "transaction_info": {
        "phone_number": "254705912645",
        "amount": 1000,
        "currency": "KES",
        "transaction_type": "B2Pochi"
    }
}

Reversal callback

Sent when a Reversal is completed or fails. On success, the original transaction is marked as reversed and funds are credited back to your payments wallet.

POST application/json
{
    "success": true,
    "reversal_transaction_id": 801,
    "original_transaction_id": 790,
    "external_reference": "SALARY-DEC-001",
    "originatorConversationID": "34567-12345-1",
    "conversationID": "AG_20241231_...",
    "transactionID": "RL78HG3X9P",
    "status": "reversed",
    "timestamp": "2024-12-31T13:05:00+03:00",
    "result": {
        "ResultCode": 0,
        "ResultDesc": "The service request is processed successfully.",
        "TransactionAmount": 1000,
        "TransactionReceipt": "RL78HG3X9P",
        "TransactionCompletedDateTime": "31.12.2024 13:05:00"
    },
    "reversal_info": {
        "amount": 1000,
        "currency": "KES",
        "original_product": "b2c",
        "transaction_type": "reversal"
    }
}

Retry Policy

Max Retries 4
Retry Intervals 5 minutes (fixed interval)
Timeout 30 seconds per attempt
Expected Response HTTP 2xx

Security Recommendations

Always verify transaction via Transactions API before processing