Overview
Fingo Pay sends webhook events to your endpoint for asynchronous transaction updates. Each event contains a type, timestamp, and transaction data.
Base Event Structure
All webhook events follow this structure:
interface WebhookEvent {
id: string; // evt_*
type: string; // Event type (see below)
created: number; // Unix timestamp
data: {
object?: Transaction; // Transaction object
id?: string; // Transaction ID
merchantTransactionId?: string;
status?: string;
message?: string;
error?: {
code: string;
message: string;
};
// ... other transaction fields
};
}
Event Types
C2B (M-Pesa Charge) Events
transaction.succeeded - Customer completed STK Push payment
transaction.failed - Payment failed (user cancelled, timeout, or error)
B2C (M-Pesa Payout) Events
transaction.creation_failed - Payout creation failed (business logic error)
payout.succeeded - B2C transfer completed successfully
payout.failed - B2C transfer failed at provider level
Other Events
transaction.created - Transaction initiated
transaction.processing - Transaction being processed
transaction.reversed - Transaction reversed/refunded
balance.updated - Account balance changed
C2B Charge Webhooks
Transaction Succeeded
Sent when the customer successfully completes the STK Push payment.
{
"id": "evt_k8m2x9p4lq7n",
"type": "transaction.succeeded",
"created": 1736697600,
"data": {
"id": "txn_01j7b6f9p5y9h",
"merchantTransactionId": "mtx_123",
"status": "completed",
"message": "The service was accepted successfully",
"amount": 10000,
"currency": "KES",
"type": "charge",
"paymentMethod": "mobile_money",
"chargedPhone": "254712345678",
"narration": "Invoice #1234",
"processor": "mpesa",
"processorReference": "ODI31ABC123XYZ",
"createdAt": "2025-01-12T14:30:00.000Z",
"updatedAt": "2025-01-12T14:30:45.000Z",
"metadata": {
"orderId": "ORD-987",
"source": "api"
}
}
}
Transaction Failed (User Cancelled)
Sent when the customer cancels, times out, or the payment fails for any reason.
{
"id": "evt_p3q7r2s5tw8y",
"type": "transaction.failed",
"created": 1736697800,
"data": {
"id": "txn_01j7b8x2m4n6k",
"merchantTransactionId": "mtx_456",
"status": "failed",
"message": "Request cancelled by user",
"amount": 5000,
"currency": "KES",
"type": "charge",
"paymentMethod": "mobile_money",
"chargedPhone": "254722334455",
"narration": "Order payment",
"processor": "mpesa",
"processorReference": "QWE78DEF456GHI",
"createdAt": "2025-01-12T15:00:00.000Z",
"updatedAt": "2025-01-12T15:01:30.000Z",
"metadata": {
"orderId": "ORD-654",
"source": "api"
}
}
}
Transaction Failed (Creation Error)
Sent when the transaction fails during creation (e.g., shortcode not found, account not configured).
{
"id": "evt_z9x8w7v6ut5s",
"type": "transaction.failed",
"created": 1736698000,
"data": {
"id": "txn_01j7c2a4b6c8d",
"merchantTransactionId": "mtx_789",
"status": "failed",
"message": "Shortcode not found",
"amount": 15000,
"currency": "KES",
"type": "charge",
"paymentMethod": "mobile_money",
"processor": "mpesa",
"createdAt": "2025-01-12T15:30:00.000Z",
"updatedAt": "2025-01-12T15:30:00.000Z",
"metadata": {
"reason": "Shortcode not found"
}
}
}
B2C Payout Webhooks
Transaction Creation Failed
Sent when payout creation fails due to non-retriable errors like insufficient balance, duplicate transaction, or account not found.
{
"id": "evt_k8x9m2y4abc1",
"type": "transaction.creation_failed",
"created": 1737043200,
"data": {
"id": "txn_abc123xyz789",
"merchantTransactionId": "order_12345",
"status": "failed",
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance on payout account"
},
"amount": 100000,
"currency": "KES",
"type": "payment",
"paymentMethod": "mobile_money",
"processor": "mpesa",
"createdAt": "2026-01-16T12:00:00.000Z",
"updatedAt": "2026-01-16T12:00:00.000Z"
}
}
INSUFFICIENT_BALANCE{
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance on payout account"
}
}
DUPLICATE_TRANSACTION{
"error": {
"code": "DUPLICATE_TRANSACTION",
"message": "Duplicate merchantTransactionId: order_12345"
}
}
ACCOUNT_NOT_FOUND{
"error": {
"code": "ACCOUNT_NOT_FOUND",
"message": "Debit account not found"
}
}
NO_PAYOUT_ACCOUNT{
"error": {
"code": "NO_PAYOUT_ACCOUNT",
"message": "No payout account configured"
}
}
Payout Succeeded
Sent when the B2C transfer to the customer’s M-Pesa wallet is successful.
{
"id": "evt_p7m3n5q2def4",
"type": "payout.succeeded",
"created": 1737043260,
"data": {
"object": {
"id": "txn_abc123xyz789",
"merchantTransactionId": "order_12345",
"status": "completed",
"message": "B2C transfer completed",
"amount": 100000,
"currency": "KES",
"type": "payment",
"paymentMethod": "mobile_money",
"chargedPhone": "+254712345678",
"narration": "Salary payment for January",
"processor": "mpesa",
"processorReference": "AG_20260116_1234567890abcdef",
"externalReference": "B2C_XYZ123ABC",
"createdAt": "2026-01-16T12:00:00.000Z",
"updatedAt": "2026-01-16T12:01:00.000Z",
"metadata": {
"employeeId": "EMP-001",
"source": "api"
}
}
}
}
Payout Failed
Sent when the M-Pesa B2C transfer fails at the provider level (e.g., invalid phone number, recipient not registered).
{
"id": "evt_f4k2j8r9ghi5",
"type": "payout.failed",
"created": 1737043260,
"data": {
"object": {
"id": "txn_abc123xyz789",
"merchantTransactionId": "order_12345",
"status": "failed",
"message": "The initiator information is invalid.",
"amount": 100000,
"currency": "KES",
"type": "payment",
"paymentMethod": "mobile_money",
"chargedPhone": "+254712345678",
"narration": "Salary payment for January",
"processor": "mpesa",
"processorReference": "AG_20260116_1234567890abcdef",
"createdAt": "2026-01-16T12:00:00.000Z",
"updatedAt": "2026-01-16T12:01:00.000Z",
"metadata": {
"employeeId": "EMP-001",
"source": "api",
"error": {
"reason": "The initiator information is invalid."
}
}
}
}
}
Webhook Signature Verification
All webhooks include signature headers for verification. See the Webhooks guide for implementation details.
X-Fingo-Signature: t=<unix>, v1=<hex_hmac>
X-Fingo-Event-Id: evt_...
Always verify webhook signatures before processing events to ensure they originate from Fingo Pay.