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

# Webhooks

> Real-time notifications for your Monieswitch integration

Webhooks enable real-time notifications for your Monieswitch integration, allowing your system to receive automatic updates about important events and transaction statuses.

## Why Use Webhooks?

Instead of repeatedly checking for updates (polling), webhooks provide instant notifications when events occur in your Monieswitch account. This approach is:

* More efficient than polling
* Not subject to rate limits
* Highly scalable
* Real-time and reliable

#### Webhook Approach

```mermaid theme={"system"}
%%{init: {'theme': 'dark', 'themeVariables': { 'fontSize': '16px', 'fontFamily': 'arial', 'nodeSpacing': 100, 'rankSpacing': 80}}}%%
graph TB
    subgraph "Webhook Process"
        A2["Your Server"] -->|Register Webhook URL| B2["Monieswitch API"]
        B2 -->|Confirm Registration| A2
        B2 -->|Event Occurs| B2
        B2 -->|Instant Notification| A2
        A2 -->|Return 200 OK| B2
    end
    N2["Webhooks: 'I'll tell you when we're there'"]
    N2 -.-> B2

    classDef server fill:#2d4059,stroke:#ffd460,color:#fff
    classDef api fill:#364f6b,stroke:#3fc1c9,color:#fff
    classDef note fill:#1a1a1a,stroke:#fc5185,color:#fff,stroke-dasharray: 5 5

    class A2 server
    class B2 api
    class N2 note
```

1. One-time webhook URL registration
2. Automatic notifications when events occur
3. Immediate updates
4. More efficient communication

#### Traditional Polling

```mermaid theme={"system"}
%%{init: {'theme': 'dark', 'themeVariables': { 'fontSize': '16px', 'fontFamily': 'arial', 'nodeSpacing': 100, 'rankSpacing': 80}}}%%
graph TB
    subgraph "Traditional Polling"
        A1["Your Server"]
        B1["Monieswitch API"]
        S1[Request Status]
        S2[Response]
        S3[Request Status Again]
        S4[Response Again]
        S5[Request Status Final]
        S6[Final Response]

        A1 --> S1 --> B1
        B1 --> S2 --> A1
        A1 --> S3 --> B1
        B1 --> S4 --> A1
        A1 --> S5 --> B1
        B1 --> S6 --> A1
    end
    N1[Polling: Constantly asking Are we there yet?]
    N1 -.-> A1

    classDef server fill:#2d4059,stroke:#ffd460,color:#fff
    classDef api fill:#364f6b,stroke:#3fc1c9,color:#fff
    classDef note fill:#1a1a1a,stroke:#fc5185,color:#fff,stroke-dasharray: 5 5
    classDef step fill:#444444,stroke:#888888,color:#fff

    class A1 server
    class B1 api
    class N1 note
    class S1,S2,S3,S4,S5,S6 step
```

1. Your server repeatedly requests updates
2. Each request requires a response
3. High number of API calls
4. Potential delays in getting updates

***

## Signature Validation

Events sent from Monieswitch carry the `x-monieswitch-signature` header. The value of this header is a HMAC SHA512 signature of the event payload signed using your secret key. Verifying the header signature should be done before processing the event.

### Example

<CodeGroup>
  ```javascript Node.js (Express) theme={"system"}
  const crypto = require("crypto");
  const secret = process.env.SECRET_KEY;

  // Using Express
  app.post("/webhook/url", function (req, res) {
    // Validate event
    const hash = crypto
      .createHmac("sha512", secret)
      .update(JSON.stringify(req.body))
      .digest("hex");
    if (hash == req.headers["x-monieswitch-signature"]) {
      // Retrieve the request's body
      const event = req.body;
      // Do something with event
    }
    res.send(200);
  });
  ```

  ```python Python (Flask) theme={"system"}
  import hashlib
  import hmac
  import json
  import os
  from flask import Flask, request

  app = Flask(__name__)
  secret = os.environ.get('SECRET_KEY')

  @app.route('/webhook/url', methods=['POST'])
  def webhook():
      # Validate event
      payload = json.dumps(request.get_json(), separators=(',', ':'))
      signature = hmac.new(
          secret.encode('utf-8'),
          payload.encode('utf-8'),
          hashlib.sha512
      ).hexdigest()

      if signature == request.headers.get('x-monieswitch-signature'):
          # Retrieve the request's body
          event = request.get_json()
          # Do something with event

      return '', 200
  ```

  ```python Python (Django) theme={"system"}
  import hashlib
  import hmac
  import json
  import os
  from django.http import HttpResponse
  from django.views.decorators.csrf import csrf_exempt
  from django.views.decorators.http import require_http_methods

  @csrf_exempt
  @require_http_methods(["POST"])
  def webhook(request):
      secret = os.environ.get('SECRET_KEY')

      # Validate event
      payload = request.body.decode('utf-8')
      signature = hmac.new(
          secret.encode('utf-8'),
          payload.encode('utf-8'),
          hashlib.sha512
      ).hexdigest()

      if signature == request.META.get('HTTP_X_MONIESWITCH_SIGNATURE'):
          # Retrieve the request's body
          event = json.loads(payload)
          # Do something with event

      return HttpResponse(status=200)
  ```

  ```php PHP theme={"system"}
  <?php
  $secret = $_ENV['SECRET_KEY'];

  // Get the payload
  $payload = file_get_contents('php://input');
  $headers = getallheaders();

  // Validate event
  $hash = hash_hmac('sha512', $payload, $secret);

  if ($hash === $headers['x-monieswitch-signature']) {
      // Retrieve the request's body
      $event = json_decode($payload, true);
      // Do something with event
  }

  http_response_code(200);
  ?>
  ```

  ```java Java (Spring Boot) theme={"system"}
  import org.springframework.web.bind.annotation.*;
  import javax.crypto.Mac;
  import javax.crypto.spec.SecretKeySpec;
  import javax.servlet.http.HttpServletRequest;
  import java.nio.charset.StandardCharsets;
  import java.security.InvalidKeyException;
  import java.security.NoSuchAlgorithmException;

  @RestController
  public class WebhookController {

      private String secret = System.getenv("SECRET_KEY");

      @PostMapping("/webhook/url")
      public void webhook(@RequestBody String payload, HttpServletRequest request) {
          try {
              // Validate event
              Mac mac = Mac.getInstance("HmacSHA512");
              SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(), "HmacSHA512");
              mac.init(secretKeySpec);

              byte[] hash = mac.doFinal(payload.getBytes(StandardCharsets.UTF_8));
              String signature = bytesToHex(hash);

              if (signature.equals(request.getHeader("x-monieswitch-signature"))) {
                  // Retrieve the request's body
                  // Do something with event
              }
          } catch (NoSuchAlgorithmException | InvalidKeyException e) {
              e.printStackTrace();
          }
      }

      private String bytesToHex(byte[] bytes) {
          StringBuilder result = new StringBuilder();
          for (byte b : bytes) {
              result.append(String.format("%02x", b));
          }
          return result.toString();
      }
  }
  ```

  ```csharp C# (.NET) theme={"system"}
  using System;
  using System.IO;
  using System.Security.Cryptography;
  using System.Text;
  using System.Text.Json;
  using Microsoft.AspNetCore.Mvc;

  [ApiController]
  [Route("[controller]")]
  public class WebhookController : ControllerBase
  {
      private readonly string _secret = Environment.GetEnvironmentVariable("SECRET_KEY");

      [HttpPost("url")]
      public IActionResult Webhook()
      {
          using var reader = new StreamReader(Request.Body);
          var payload = reader.ReadToEnd();

          // Validate event
          using var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(_secret));
          var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
          var signature = Convert.ToHexString(hash).ToLower();

          if (signature == Request.Headers["x-monieswitch-signature"])
          {
              // Retrieve the request's body
              var eventData = JsonSerializer.Deserialize<object>(payload);
              // Do something with event
          }

          return Ok();
      }
  }
  ```

  ```go Go (Gin) theme={"system"}
  package main

  import (
      "crypto/hmac"
      "crypto/sha512"
      "encoding/hex"
      "encoding/json"
      "io/ioutil"
      "net/http"
      "os"

      "github.com/gin-gonic/gin"
  )

  func webhookHandler(c *gin.Context) {
      secret := os.Getenv("SECRET_KEY")

      // Read the request body
      body, err := ioutil.ReadAll(c.Request.Body)
      if err != nil {
          c.Status(http.StatusBadRequest)
          return
      }

      // Validate event
      h := hmac.New(sha512.New, []byte(secret))
      h.Write(body)
      signature := hex.EncodeToString(h.Sum(nil))

      if signature == c.GetHeader("x-monieswitch-signature") {
          // Retrieve the request's body
          var event map[string]interface{}
          json.Unmarshal(body, &event)
          // Do something with event
      }

      c.Status(http.StatusOK)
  }

  func main() {
      r := gin.Default()
      r.POST("/webhook/url", webhookHandler)
      r.Run()
  }
  ```

  ```ruby Ruby (Rails) theme={"system"}
  class WebhookController < ApplicationController
    skip_before_action :verify_authenticity_token

    def webhook
      secret = ENV['SECRET_KEY']
      payload = request.body.read

      # Validate event
      signature = OpenSSL::HMAC.hexdigest('SHA512', secret, payload)

      if signature == request.headers['x-monieswitch-signature']
        # Retrieve the request's body
        event = JSON.parse(payload)
        # Do something with event
      end

      head :ok
    end
  end
  ```
</CodeGroup>

## Implementation Guide

### 1. Creating Your Webhook Endpoint

Set up a POST endpoint on your server to receive webhook notifications. Your endpoint should:

* Accept JSON payloads
* Return a 200 OK response
* Process events asynchronously

Example implementation:

```javascript theme={"system"}
app.post("/webhooks", function (req, res) {
  res.status(200).send();

  // Process the event asynchronously
  const event = req.body;
  processWebhookEvent(event);
});
```

### 2. Update Webhook URL in Dashboard

In your Monieswitch account settings, add your webhook URL to receive notifications. This URL should be publicly accessible and secure.

## Event Types Reference

### Payout Events

<Tabs>
  <Tab title="Payout Pending">
    ```json theme={"system"}
    {
      "event": "payout.pending",
      "status": "PENDING",
      "amount": 500,
      "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
      "narration": "testing",
      "beneficiaryBankCode": "090197",
      "beneficiaryAccountNumber": "2034589705",
      "description": "₦500.00 transferred to SIMI MICHELLE",
      "beneficiaryAccountName": "SIMI MICHELLE",
      "charges": 10,
      "totalAmount": 510,
      "beneficiaryBankName": "ABU MICROFINANCE BANK",
      "originatorWalletId": "4fa8008a-5c42-4ce0-8727-acce575496b6",
      "originatorAccountName": "ID Stores",
      "originatorAccountNumber": "4475364845",
      "paidAt": "2025-05-07T12:40:32Z",
      "transactionId": "1ba0105a-76aa-4f10-ae49-f610aad45dab",
      "reference": "kSh1NfD0gfwz3xPzV0ApFLfcp5a2TGZwCkg0",
      "sessionId": "999270250507124032023825430717"
    }
    ```
  </Tab>

  <Tab title="Payout Success">
    ```json theme={"system"}
    {
      "event": "payout.success",
      "status": "SUCCESS",
      "amount": 500,
      "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
      "narration": "testing",
      "beneficiaryBankCode": "090197",
      "beneficiaryAccountNumber": "2034589705",
      "description": "₦500.00 transferred to SIMI MICHELLE",
      "beneficiaryAccountName": "SIMI MICHELLE",
      "charges": 10,
      "totalAmount": 510,
      "beneficiaryBankName": "ABU MICROFINANCE BANK",
      "originatorWalletId": "4fa8008a-5c42-4ce0-8727-acce575496b6",
      "originatorAccountName": "ID Stores",
      "originatorAccountNumber": "4475364845",
      "paidAt": "2025-05-07T12:40:32Z",
      "transactionId": "1ba0105a-76aa-4f10-ae49-f610aad45dab",
      "reference": "kSh1NfD0gfwz3xPzV0ApFLfcp5a2TGZwCkg0",
      "sessionId": "999270250507124032023825430717"
    }
    ```
  </Tab>

  <Tab title="Payout Failed">
    ```json theme={"system"}
    {
      "event": "payout.failed",
      "status": "FAILED",
      "amount": 500,
      "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
      "narration": "testing",
      "beneficiaryBankCode": "090197",
      "beneficiaryAccountNumber": "2034589705",
      "description": "₦500.00 transferred to SIMI MICHELLE",
      "beneficiaryAccountName": "SIMI MICHELLE",
      "charges": 10,
      "totalAmount": 510,
      "beneficiaryBankName": "ABU MICROFINANCE BANK",
      "originatorWalletId": "4fa8008a-5c42-4ce0-8727-acce575496b6",
      "originatorAccountName": "ID Stores",
      "originatorAccountNumber": "4475364845",
      "paidAt": "2025-05-07T12:40:32Z",
      "transactionId": "1ba0105a-76aa-4f10-ae49-f610aad45dab",
      "reference": "kSh1NfD0gfwz3xPzV0ApFLfcp5a2TGZwCkg0",
      "sessionId": "999270250507124032023825430717"
    }
    ```
  </Tab>
</Tabs>

### Static Account Funding Events

<Tabs>
  <Tab title="Pending Bank Funding">
    ```json theme={"system"}
    {
      "event": "static.account.payment.pending",
      "type": "CREDIT",
      "status": "PENDING",
      "mode": "SANDBOX",
      "walletId": "4fa8008a-5c42-4ce0-8727-acce575496b6",
      "amount": 100000,
      "paidAt": "2025-05-07T12:59:50.641Z",
      "sessionId": "999270250507125950030527152284",
      "reference": "l-m8KbrPKoYV128VPckeKkeXaeedAsqFyMyOHu",
      "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
      "charges": 1550,
      "settledAmount": 98450,
      "userId": "573186c9-61bf-41fd-9616-75e0be705625",
      "walletType": "STATIC",
      "channelCode": "2",
      "transactionReference": "l-m8KbrPKoYV128VPckeKkeXaeedAsqFyMyOHu",
      "narration": "Sandbox Account funding.",
      "beneficiaryBankName": "XpressWallet",
      "beneficiaryBankCode": "999270",
      "beneficiaryBankVerificationNumber": "",
      "beneficiaryAccountName": "ID Stores",
      "beneficiaryAccountNumber": "4475364845",
      "originatorBankCode": "999270",
      "originatorBankName": "Monieswitch Test Bank",
      "originatorAccountName": "Emmanuel",
      "originatorAccountNumber": "0167421242",
      "originatorBankVerificationNumber": "",
      "description": "₦100,000.00 received from Emmanuel",
      "transactionId": "ff7b7e39-e473-4250-8724-797d7820f0bd"
    }
    ```
  </Tab>

  <Tab title="Successful Bank Funding">
    ```json theme={"system"}
    {
      "event": "static.account.payment.success",
      "type": "CREDIT",
      "status": "SUCCESS",
      "mode": "SANDBOX",
      "walletId": "4fa8008a-5c42-4ce0-8727-acce575496b6",
      "amount": 100000,
      "paidAt": "2025-05-07T12:59:50.641Z",
      "sessionId": "999270250507125950030527152284",
      "reference": "l-m8KbrPKoYV128VPckeKkeXaeedAsqFyMyOHu",
      "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
      "charges": 1550,
      "settledAmount": 98450,
      "userId": "573186c9-61bf-41fd-9616-75e0be705625",
      "walletType": "STATIC",
      "channelCode": "2",
      "transactionReference": "l-m8KbrPKoYV128VPckeKkeXaeedAsqFyMyOHu",
      "narration": "Sandbox Account funding.",
      "beneficiaryBankName": "XpressWallet",
      "beneficiaryBankCode": "999270",
      "beneficiaryBankVerificationNumber": "",
      "beneficiaryAccountName": "ID Stores",
      "beneficiaryAccountNumber": "4475364845",
      "originatorBankCode": "999270",
      "originatorBankName": "Monieswitch Test Bank",
      "originatorAccountName": "Emmanuel",
      "originatorAccountNumber": "0167421242",
      "originatorBankVerificationNumber": "",
      "description": "₦100,000.00 received from Emmanuel",
      "transactionId": "ff7b7e39-e473-4250-8724-797d7820f0bd"
    }
    ```
  </Tab>

  <Tab title="Failed Bank Funding">
    ```json theme={"system"}
    {
      "event": "static.account.payment.failed",
      "type": "CREDIT",
      "status": "FAILED",
      "mode": "SANDBOX",
      "walletId": "4fa8008a-5c42-4ce0-8727-acce575496b6",
      "amount": 100000,
      "paidAt": "2025-05-07T12:59:50.641Z",
      "sessionId": "999270250507125950030527152284",
      "reference": "l-m8KbrPKoYV128VPckeKkeXaeedAsqFyMyOHu",
      "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
      "charges": 1550,
      "settledAmount": 98450,
      "userId": "573186c9-61bf-41fd-9616-75e0be705625",
      "walletType": "STATIC",
      "channelCode": "2",
      "transactionReference": "l-m8KbrPKoYV128VPckeKkeXaeedAsqFyMyOHu",
      "narration": "Sandbox Account funding.",
      "beneficiaryBankName": "XpressWallet",
      "beneficiaryBankCode": "999270",
      "beneficiaryBankVerificationNumber": "",
      "beneficiaryAccountName": "ID Stores",
      "beneficiaryAccountNumber": "4475364845",
      "originatorBankCode": "999270",
      "originatorBankName": "Monieswitch Test Bank",
      "originatorAccountName": "Emmanuel",
      "originatorAccountNumber": "0167421242",
      "originatorBankVerificationNumber": "",
      "description": "₦100,000.00 received from Emmanuel",
      "transactionId": "ff7b7e39-e473-4250-8724-797d7820f0bd"
    }
    ```
  </Tab>
</Tabs>

### Virtual Account Collection Events

<Tabs>
  <Tab title="Payment Success">
    ```json theme={"system"}
    {
      "event": "virtual.account.payment.success",
      "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
      "status": "success",
      "amount": 2000,
      "paidAt": "2025-05-07T13:06:20.719Z",
      "reference": "l-dETwqrcxjwnAba2kbr4StCHuSndsl9sBq8mz",
      "narration": "Funding Virtual Account 4460895224 - ID Stores-Fast payment",
      "transactionId": "f5e81a9a-c55a-4b6e-a153-b3e513759ff6",
      "amountPaid": 2000,
      "settledAmount": 1970,
      "settlementCharge": 30,
      "customerReference": "o8Vq9vejST2hWf5WyLK85hAGBHMW7jBtZsaV",
      "hasActiveSubaccount": false,
      "originatorBankCode": "999270",
      "originatorBankName": "Monieswitch Test Bank",
      "originatorAccountName": "Emmanuel",
      "sessionId": "999270250507130620813261532358",
      "originatorAccountNumber": "0167421242",
      "beneficiaryBankCode": "999270",
      "beneficiaryBankName": "Xpresswallet",
      "beneficiaryAccountName": "ID Stores-Fast payment",
      "beneficiaryAccountNumber": "4460895224"
    }
    ```
  </Tab>

  <Tab title="Payment Pending">
    ```json theme={"system"}
    {
      "event": "virtual.account.payment.pending",
      "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
      "status": "pending",
      "amount": 2000,
      "paidAt": "2025-05-07T13:06:20.719Z",
      "reference": "l-dETwqrcxjwnAba2kbr4StCHuSndsl9sBq8mz",
      "narration": "Funding Virtual Account 4460895224 - ID Stores-Fast payment",
      "transactionId": "f5e81a9a-c55a-4b6e-a153-b3e513759ff6",
      "amountPaid": 2000,
      "settledAmount": 1970,
      "settlementCharge": 30,
      "customerReference": "o8Vq9vejST2hWf5WyLK85hAGBHMW7jBtZsaV",
      "hasActiveSubaccount": false,
      "originatorBankCode": "999270",
      "originatorBankName": "Monieswitch Test Bank",
      "originatorAccountName": "Emmanuel",
      "sessionId": "999270250507130620813261532358",
      "originatorAccountNumber": "0167421242",
      "beneficiaryBankCode": "999270",
      "beneficiaryBankName": "Xpresswallet",
      "beneficiaryAccountName": "ID Stores-Fast payment",
      "beneficiaryAccountNumber": "4460895224"
    }
    ```
  </Tab>

  <Tab title="Payment Failed">
    ```json theme={"system"}
    {
      "event": "virtual.account.payment.failed",
      "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
      "status": "failed",
      "amount": 2000,
      "paidAt": "2025-05-07T13:06:20.719Z",
      "reference": "l-dETwqrcxjwnAba2kbr4StCHuSndsl9sBq8mz",
      "narration": "Funding Virtual Account 4460895224 - ID Stores-Fast payment",
      "transactionId": "f5e81a9a-c55a-4b6e-a153-b3e513759ff6",
      "amountPaid": 2000,
      "settledAmount": 1970,
      "settlementCharge": 30,
      "customerReference": "o8Vq9vejST2hWf5WyLK85hAGBHMW7jBtZsaV",
      "hasActiveSubaccount": false,
      "originatorBankCode": "999270",
      "originatorBankName": "Monieswitch Test Bank",
      "originatorAccountName": "Emmanuel",
      "sessionId": "999270250507130620813261532358",
      "originatorAccountNumber": "0167421242",
      "beneficiaryBankCode": "999270",
      "beneficiaryBankName": "Xpresswallet",
      "beneficiaryAccountName": "ID Stores-Fast payment",
      "beneficiaryAccountNumber": "4460895224"
    }
    ```
  </Tab>

  <Tab title="Card Collection Success">
    ```json theme={"system"}
    {
      "event": "virtual.account.payment.success",
      "merchantId": "3aed8fe9-2c60-48fe-bea4-71ea8c8f3c84",
      "rrn": "000106923853",
      "last4": "7499",
      "scheme": "VERVE",
      "paidAt": "2025-07-22T04:03:52",
      "paymentMethod": "Card",
      "currency": "NGN",
      "terminalId": "3PXM0001",
      "cardNumber": "",
      "status": "COMPLETED",
      "amount": 450,
      "transactionId": "8f666656-2926-424c-b75d-aff95ade3188",
      "reference": "m0mSHeGkKb3MPKdMiwR5TtTDgRSn0Q",
      "customerMetadata": {
        "isCheckoutAccount": true,
        "checkoutId": "593c150c-2a91-4d78-a061-333879d64e0d",
        "reference": "m0mSHeGkKb3MPKdMiwR5TtTDgRSn0Q",
        "hello": "hello world"
      },
      "customerReference": "m0mSHeGkKb3MPKdMiwR5TtTDgRSn0Q",
      "amountPaid": 450,
      "settledAmount": 442.35,
      "settlementCharge": 7.65,
      "hasActiveSubaccount": false
    }
    ```
  </Tab>
</Tabs>

### Wallet Debit

```json theme={"system"}
{
  "event": "debit.wallet",
  "paidAt": "2025-06-24T12:38:51Z",
  "reference": "4usHc2qro2X8UUNMjP3rypl2L33HpS74KVK8",
  "totalAmount": 9800,
  "charges": 0,
  "status": "SUCCESS",
  "amount": 9800,
  "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
  "walletId": "dc55f7ab-e750-41d2-8e04-288a2b3f0a1c",
  "narration": "Testing",
  "originatorBankName": "Xpresswallet",
  "originatorBankCode": "999270",
  "originatorAccountName": "EmmaBaba",
  "originatorAccountNumber": "4499466143",
  "beneficiaryBankCode": "999270",
  "beneficiaryBankName": "Xpresswallet",
  "beneficiaryAccountName": "ID Stores",
  "beneficiaryAccountNumber": "4475364845",
  "description": "₦9,800.00 debitted from EmmaBaba",
  "transactionId": "1061c238-30b3-4387-88f1-3df458372d1f"
}
```

### Card Events

<Tabs>
  <Tab title="Card Settlement">
    ```json theme={"system"}
    {
      "event": "card.settlement",
      "mode": "SANDBOX",
      "amount": 400,
      "merchantId": "3aed8fe9-2c60-48fe-bea4-71ea8c8f3c84",
      "settlementDate": "2025-08-28",
      "status": "SUCCESSFUL",
      "settlementId": "ad8ecbaa-13b9-46a5-a7b9-79b1f83a1afd",
      "category": "CARD_SETTLEMENT",
      "isAutoSettlementEnabled": false
    }
    ```
  </Tab>

  <Tab title="Card Debit">
    ```json theme={"system"}
    {
      "event": "card.debit",
      "paidAt": "2025-07-15T14:44:41.329Z",
      "reference": "IM3noVYw1gXBslQTFCeX5HiggucdA7",
      "description": "Card debit transaction of ₦300.00",
      "cardId": "6b29aa09-05b9-4f78-9745-c16c3dbddf6a",
      "mode": "SANDBOX",
      "walletId": "520b2b20-c8ff-4154-94ce-64ae2f2de4e3",
      "amount": 300,
      "charges": 0,
      "currency": "NGN",
      "transactionType": "Purchase",
      "transactionId": "51f6633a-b64e-4317-8467-9db1ad4a4d83"
    }
    ```
  </Tab>

  <Tab title="Card Reversal">
    ```json theme={"system"}
    {
      "event": "card.reversal",
      "reversedAt": "2025-07-15T15:08:25.342Z",
      "description": "Card debit reversal of ₦200.00",
      "cardId": "6b29aa09-05b9-4f78-9745-c16c3dbddf6a",
      "mode": "SANDBOX",
      "walletId": "520b2b20-c8ff-4154-94ce-64ae2f2de4e3",
      "amount": 200,
      "charges": 0,
      "reference": "r-Ic7jnFX0AJ4EcoEGvi0Rj1gqUbqzXV",
      "currency": "NGN",
      "transactionType": "General Credit",
      "originalTransactionId": "9ef85f65-8447-43c1-8f22-c507a83b4a57",
      "originalTransactionReference": "Ic7jnFX0AJ4EcoEGvi0Rj1gqUbqzXV",
      "transactionId": "db4352a9-aca0-4f23-8d4d-e515e0eca9a2"
    }
    ```
  </Tab>

  <Tab title="Place Lien">
    ```json theme={"system"}
    {
      "event": "card.place.lien",
      "paidAt": "2025-07-15T15:23:50.188Z",
      "reference": "FKjZ3ghWlQeWZ4VBTLi6WikISVrwKL",
      "description": "Card debit of ₦100.00 pending",
      "cardId": "6b29aa09-05b9-4f78-9745-c16c3dbddf6a",
      "mode": "SANDBOX",
      "walletId": "520b2b20-c8ff-4154-94ce-64ae2f2de4e3",
      "amount": 100,
      "charges": 0,
      "currency": "NGN",
      "transactionType": "Purchase",
      "transactionId": "84efc927-fb50-481b-aaf8-507315c4a348"
    }
    ```
  </Tab>

  <Tab title="Debit Lien">
    ```json theme={"system"}
    {
      "event": "card.debit.lien",
      "paidAt": "2025-07-15T15:30:30.087Z",
      "reference": "5X8rHYI5cuAVSKxBYql15neLGl97hN",
      "description": "Card debit of ₦100.00 pending",
      "cardId": "6b29aa09-05b9-4f78-9745-c16c3dbddf6a",
      "mode": "SANDBOX",
      "walletId": "520b2b20-c8ff-4154-94ce-64ae2f2de4e3",
      "amount": 100,
      "charges": 0,
      "currency": "NGN",
      "transactionId": "84efc927-fb50-481b-aaf8-507315c4a348"
    }
    ```
  </Tab>
</Tabs>

### Sandbox Funding

```json theme={"system"}
{
  "event": "sandbox.fund.success",
  "type": "CREDIT",
  "status": "SUCCESS",
  "mode": "SANDBOX",
  "walletId": "4fa8008a-5c42-4ce0-8727-acce575496b6",
  "amount": 10000,
  "paidAt": "2025-05-07T12:55:23Z",
  "merchantId": "b7205b06-f71f-417f-8f5f-0245ca2d3787",
  "sessionId": "25752448303645411876949004421594",
  "reference": "YDlKPE2W90ZPOCPZmqUsJmNw0cxrioYFnUtY",
  "charges": 0,
  "settledAmount": 10000,
  "channelCode": "2",
  "transactionReference": "YDlKPE2W90ZPOCPZmqUsJmNw0cxrioYFnUtY",
  "narration": "Sandbox Funding",
  "beneficiaryBankName": "Xpress Wallet",
  "beneficiaryBankCode": "999270",
  "beneficiaryBankVerificationNumber": "00000000001",
  "beneficiaryAccountName": "ID Stores",
  "beneficiaryAccountNumber": "4475364845",
  "originatorBankCode": "999270",
  "originatorBankName": "Monieswitch Test Bank",
  "originatorAccountName": "Monieswitch Test Funding",
  "originatorAccountNumber": "0987654321",
  "originatorBankVerificationNumber": "00000000001",
  "description": "₦10,000.00 received from Monieswitch Test Funding"
}
```

## Status Code Reference

| Event Type                        | Status Code  | Meaning                              |
| --------------------------------- | ------------ | ------------------------------------ |
| `virtual.account.payment.success` | `success`    | Payment confirmed and processed      |
| `virtual.account.payment.pending` | `pending`    | Payment initiated but not completed  |
| `virtual.account.payment.failed`  | `failed`     | Payment attempt failed               |
| `payout.success`                  | `SUCCESS`    | Transfer completed successfully      |
| `payout.pending`                  | `PENDING`    | Transfer initiated but not completed |
| `payout.failed`                   | `FAILED`     | Transfer failed to complete          |
| `static.account.payment.success`  | `SUCCESS`    | Static account funding successful    |
| `static.account.payment.pending`  | `PENDING`    | Static account funding pending       |
| `static.account.payment.failed`   | `FAILED`     | Static account funding failed        |
| `debit.wallet`                    | `SUCCESS`    | Wallet debit transaction completed   |
| `sandbox.fund.success`            | `SUCCESS`    | Sandbox funding successful           |
| `card.settlement`                 | `SUCCESSFUL` | Card settlement completed            |

## Best Practices

### 1. Event Handling

* Always verify event type before processing
* Implement idempotency checks using reference/transaction IDs
* Handle each event type independently
* Log all received events for audit purposes

### 2. Status Verification

* Confirm both event type and status match
* Check failure reasons for failed events
* Implement appropriate error handling
* Validate webhook signature before processing

### 3. Processing Order

* Process `pending` events before `success` or `failed`
* Store `pending` state for reconciliation
* Update records for both success and failure events
* Maintain event sequence for audit trails

### 4. Failure Handling

* Implement retry logic where appropriate
* Store failure reasons for analysis
* Send appropriate notifications
* Consider automated recovery flows

### 5. Security

* Always validate webhook signatures
* Use HTTPS for webhook endpoints
* Implement proper authentication
* Log security events for monitoring
