Skip to main content

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.