Event Reference
Every webhook payload has the same envelope structure with an event field identifying the type and a transaction object with the full details.
Payload envelope
Webhook payload structure
{
"event": "payment.completed",
"transaction": { ... }
}Event types
payment.completed
Fired when a collection is successfully completed and funds have been credited to your wallet.
payment.completed
{
"event": "payment.completed",
"transaction": {
"id": "txn_01j2k3m4n5p6q7r8s9t0",
"reference": "AXP-SXSZF5H6",
"type": "COLLECTION",
"amount": 25000,
"fee": 0,
"netAmount": 25000,
"channel": "MPESA",
"status": "COMPLETED",
"buyerPhone": "+255712345678",
"buyerName": "Amina Hassan",
"metadata": { "orderId": "ORD-1042" },
"providerReference": "MP2506091430001",
"completedAt": "2025-06-09T14: 30: 45.000Z"
}
}payment.failed
Fired when a collection fails — customer declined, timeout, insufficient funds, or network error.
payment.failed
{
"event": "payment.failed",
"transaction": {
"id": "txn_01j2k3m4n5p6q7r8s9t0",
"reference": "AXP-SXSZF5H6",
"type": "COLLECTION",
"amount": 25000,
"channel": "MPESA",
"status": "FAILED",
"failureReason": "Customer declined the payment request",
"buyerPhone": "+255712345678",
"buyerName": "Amina Hassan",
"metadata": { "orderId": "ORD-1042" },
"failedAt": "2025-06-09T14: 32: 00.000Z"
}
}payout.completed
Fired when a disbursement is successfully delivered to the recipient.
payout.completed
{
"event": "payout.completed",
"transaction": {
"id": "txn_01j2k3m4n5p6q7r8s9t1",
"reference": "AXP-DXYZW1A2",
"type": "DISBURSEMENT",
"amount": 50000,
"fee": 0,
"netAmount": 50000,
"channel": "MPESA",
"status": "COMPLETED",
"recipientPhone": "+255712345678",
"recipientName": "John Mwangi",
"providerReference": "MP2506091500001",
"completedAt": "2025-06-09T15: 00: 30.000Z"
}
}payout.failed
Fired when a disbursement fails. Funds are returned to your wallet.
payout.failed
{
"event": "payout.failed",
"transaction": {
"id": "txn_01j2k3m4n5p6q7r8s9t1",
"reference": "AXP-DXYZW1A2",
"type": "DISBURSEMENT",
"amount": 50000,
"channel": "MPESA",
"status": "FAILED",
"failureReason": "Recipient account not registered",
"recipientPhone": "+255712345678",
"failedAt": "2025-06-09T15: 02: 00.000Z"
}
}✅Always check
event.transaction.status rather than inferring status from the event name — this makes your handler resilient to future event additions.