> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fingopay.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Events

> Webhook event payloads for transaction.* events across collections and payouts

## 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:

```ts theme={"dark"}
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;
    subMerchantId?: string;
    subMerchantDetails?: {
      name?: string;
      legalName?: string;
      riskLevel?: 'low' | 'medium' | 'high';
    };
    status?: string;
    message?: string;
    error?: {
      code: string;
      message: string;
    };
    // ... other transaction fields
  };
}
```

## Event Types

### C2B (M-Pesa Charge) Events

* `transaction.creation_failed` - Collections creation failed (business logic error)
* `transaction.succeeded` - Customer completed STK Push payment
* `transaction.failed` - Payment failed (user cancelled, timeout, or error)

### Payout Transaction Events

* `transaction.creation_failed` - Payout creation failed (business logic error)
* `transaction.succeeded` - Payout completed successfully
* `transaction.failed` - Payout failed

### Other transaction events

* `transaction.created` - Transaction initiated
* `transaction.processing` - Transaction being processed
* `transaction.reversed` - Transaction reversed/refunded

<Info>
  `transaction.*` is the webhook namespace used across all transaction categories.
</Info>

***

## C2B Charge Webhooks

### Transaction Succeeded

Sent when the customer successfully completes the STK Push payment.

<ResponseExample>
  ```json transaction.succeeded theme={"dark"}
  {
    "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",
      "subMerchantId": "SM-NAIROBI-001",
      "subMerchantDetails": {
        "name": "Nairobi West Branch",
        "riskLevel": "medium"
      },
      "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"
      }
    }
  }
  ```
</ResponseExample>

### Transaction Failed (User Cancelled)

Sent when the customer cancels, times out, or the payment fails for any reason.

<ResponseExample>
  ```json transaction.failed theme={"dark"}
  {
    "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"
      }
    }
  }
  ```
</ResponseExample>

### Transaction Failed (Creation Error)

Sent when the transaction fails during creation (e.g., shortcode not found, account not configured).

<ResponseExample>
  ```json transaction.failed theme={"dark"}
  {
    "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",
      "subMerchantId": "SM-NAIROBI-001",
      "subMerchantDetails": {
        "name": "Nairobi West Branch",
        "riskLevel": "high"
      },
      "processor": "mpesa",
      "createdAt": "2025-01-12T15:30:00.000Z",
      "updatedAt": "2025-01-12T15:30:00.000Z",
      "metadata": {
        "reason": "Shortcode not found"
      }
    }
  }
  ```
</ResponseExample>

***

## 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.

<ResponseExample>
  ```json transaction.creation_failed theme={"dark"}
  {
    "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"
    }
  }
  ```
</ResponseExample>

<AccordionGroup>
  <Accordion title="Common error codes">
    **INSUFFICIENT\_BALANCE**

    ```json theme={"dark"}
    {
      "error": {
        "code": "INSUFFICIENT_BALANCE",
        "message": "Insufficient balance on payout account"
      }
    }
    ```

    **DUPLICATE\_TRANSACTION**

    ```json theme={"dark"}
    {
      "error": {
        "code": "DUPLICATE_TRANSACTION",
        "message": "Duplicate merchantTransactionId: order_12345"
      }
    }
    ```

    **ACCOUNT\_NOT\_FOUND**

    ```json theme={"dark"}
    {
      "error": {
        "code": "ACCOUNT_NOT_FOUND",
        "message": "Debit account not found"
      }
    }
    ```

    **NO\_PAYOUT\_ACCOUNT**

    ```json theme={"dark"}
    {
      "error": {
        "code": "NO_PAYOUT_ACCOUNT",
        "message": "No payout account configured"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Transaction Succeeded (Payout)

Sent when the B2C transfer to the customer's M-Pesa wallet is successful.

<ResponseExample>
  ```json transaction.succeeded theme={"dark"}
  {
    "id": "evt_p7m3n5q2def4",
    "type": "transaction.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"
        }
      }
    }
  }
  ```
</ResponseExample>

### Transaction Failed (Payout)

Sent when the M-Pesa B2C transfer fails at the provider level (e.g., invalid phone number, recipient not registered).

<ResponseExample>
  ```json transaction.failed theme={"dark"}
  {
    "id": "evt_f4k2j8r9ghi5",
    "type": "transaction.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."
          }
        }
      }
    }
  }
  ```
</ResponseExample>

***

## Webhook Signature Verification

All webhooks include signature headers for verification. See the [Webhooks guide](/webhooks) for implementation details.

```http theme={"dark"}
X-Fingo-Signature: t=<unix>, v1=<hex_hmac>
X-Fingo-Event-Id: evt_...
```

<Tip>
  Always verify webhook signatures before processing events to ensure they originate from Fingo Pay.
</Tip>
