Webhooks

Webhooks is an API concept that enables applications to automatically communicate with each other without constant polling. Monnify integration sends notifications to a URL on the merchants’ server when specific events such as when payments are being received or when settlements are made to your account, allowing further actions such as sending an email or providing value to the user.

Configuring webhooks on Monnify UI

Scroll down to the Developer page on the left navigation menu and then proceed to the Webhook URLs section to input your URL’s i.e Transaction Completion, Refund Completion, Disbursement and Settlement. Once you've pasted your webhook details click save and you are good to go!


Below is a sample image on how to input your urls on the monnify dashboard



Monnify supports webhooks for various events like card transactions, settlement and disbursement completion, and refunds.

To implement webhooks on your Monnify integration, it is recommended to follow certain best practices such as validating transaction hash, whitelisting Monnify's IP address, checking for duplicate notifications, and processing complex logic after acknowledging receipt of the notification with a 200 HTTP status code. These practices ensure the integrity and security of the payload, prevent unauthorized requests, avoid redundant processing, and prevent time-out issues.

Monnify Webhook Events and Structure

As part of the Monnify integration, notifications are automatically sent to your system when certain actions are completed. These notifications trigger corresponding activities on your system, and you can specify URLs for certain activities on your integration.


The notifications include an event-type property that indicates what action has taken place, as well as event data containing details of the event.


Supported notification event types on Monnify include:


  1. Successful Collection (for successful payments made on your account).
  2. Successful Disbursement (for disbursement transactions with a successful definite status).

  3. Failed Disbursement (for failed disbursement transactions).
  4. Reversed Disbursement (for reversed disbursement transactions).
  5. Successful Refund (for successfully processed initiated refunds).
  6. Failed Refund (for failed initiated refunds).
  7. Settlement Completion (for successfully processed settlements to your bank account or wallet).

  8. Mandate Status Change (This is sent when the status of a mandate changes from PENDING to FAILED or CANCELLED or ACTIVATED etc).

  9. Wallet activity notification (For notifying merchants of credits and debits to their Main or SubWallets).


Structure and Sample

A typical event notification structure is of the format:

1{
2  "eventType": "type_of_event",
3  "eventData": {
4    "prop1": "value1",
5    "prop2": "value2"
6  }
7}

Transaction Hash Computation

As a security measure, Monnify computes a hash of the request body whenever it sends a notification and includes it in the request header with the key 'monnify-signature'. To ensure the notification is valid and authorized, you should also calculate the hash and compare it to the one sent by Monnify before accepting or acting on the notification.


To calculate the hash, you can use a SHA-512 encoding of your client secret key and the object of the request body. The formula is: SHA-512(client secret key + object of request body).


Sample Examples:

Sample Client Key: 91MUDL9N6U3BQRXBQ2PJ9M0PW4J22M1Y

Sample Request:

1{
2  "eventData": {
3    "product": {
4      "reference": "111222333",
5      "type": "OFFLINE_PAYMENT_AGENT"
6    },
7    "transactionReference": "MNFY|76|20211117154810|000001",
8    "paymentReference": "0.01462001097368737",
9    "paidOn": "17/11/2021 3:48:10 PM",
10    "paymentDescription": "Mockaroo Jesse",
11    "metaData": {},
12    "destinationAccountInformation": {},
13    "paymentSourceInformation": {},
14    "amountPaid": 78000,
15    "totalPayable": 78000,
16    "offlineProductInformation": {
17      "code": "41470",
18      "type": "DYNAMIC"
19    },
20    "cardDetails": {},
21    "paymentMethod": "CASH",
22    "currency": "NGN",
23    "settlementAmount": 77600,
24    "paymentStatus": "PAID",
25    "customer": {
26      "name": "Mockaroo Jesse",
27      "email": "[email protected]"
28    }
29  },
30  "eventType": "SUCCESSFUL_TRANSACTION"
31}

Hashed Value:

f04fb635e04d71648bd3cc7999003da6861483342c856d05ddfa9b2dafacb87 3b0de1d0f8f67405d0010b4348b721c49fa171d317972618debba6b638aedcd3c


Computing Hash in Nodejs

1const { sha512 } = require("js-sha512");
2
3const DEFAULT_MERCHANT_CLIENT_SECRET = "91MUDL9N6U3BQRXBQ2PJ9M0PW4J22M1Y";
4
5const computeHash = (requestBody) => {
6const result = sha512.hmac(DEFAULT_MERCHANT_CLIENT_SECRET, requestBody);
7return result;
8};
9
10const stringifiedRequestBody = JSON.stringify({
11eventData: {
12  product: {
13    reference: "111222333",
14    type: "OFFLINE_PAYMENT_AGENT",
15  },
16  transactionReference: "MNFY|76|20211117154810|000001",
17  paymentReference: "0.01462001097368737",
18  paidOn: "17/11/2021 3:48:10 PM",
19  paymentDescription: "Mockaroo Jesse",
20  metaData: {},
21  destinationAccountInformation: {},
22  paymentSourceInformation: {},
23  amountPaid: 78000,
24  totalPayable: 78000,
25  offlineProductInformation: {
26    code: "41470",
27    type: "DYNAMIC",
28  },
29  cardDetails: {},
30  paymentMethod: "CASH",
31  currency: "NGN",
32  settlementAmount: 77600,
33  paymentStatus: "PAID",
34  customer: {
35    name: "Mockaroo Jesse",
36    email: "[email protected]",
37  },
38},
39eventType: "SUCCESSFUL_TRANSACTION",
40});
41
42const computedHash = computeHash(stringifiedRequestBody);
43console.log("Computed hash:", computedHash);


Computing Hash in PHP

1<?php
2
3class CustomTransactionHashUtil
4{
5  public static function computeSHA512TransactionHash($stringifiedData, $clientSecret)
6  {
7      return hash_hmac('sha512', $stringifiedData, $clientSecret);
8  }
9}
10
11$DEFAULT_MERCHANT_CLIENT_SECRET = '91MUDL9N6U3BQRXBQ2PJ9M0PW4J22M1Y';
12
13$data = json_encode([
14  "eventData" => [
15      "product" => [
16          "reference" => "111222333",
17          "type" => "OFFLINE_PAYMENT_AGENT",
18      ],
19      "transactionReference" => "MNFY|76|20211117154810|000001",
20      "paymentReference" => "0.01462001097368737",
21      "paidOn" => "17/11/2021 3:48:10 PM",
22      "paymentDescription" => "Mockaroo Jesse",
23      "metaData" => new stdClass(),
24      "destinationAccountInformation" => new stdClass(),
25      "paymentSourceInformation" => new stdClass(),
26      "amountPaid" => 78000,
27      "totalPayable" => 78000,
28      "offlineProductInformation" => [
29          "code" => "41470",
30          "type" => "DYNAMIC",
31      ],
32      "cardDetails" => new stdClass(),
33      "paymentMethod" => "CASH",
34      "currency" => "NGN",
35      "settlementAmount" => 77600,
36      "paymentStatus" => "PAID",
37      "customer" => [
38          "name" => "Mockaroo Jesse",
39          "email" => "[email protected]",
40      ],
41  ],
42  "eventType" => "SUCCESSFUL_TRANSACTION",
43], JSON_UNESCAPED_SLASHES);
44
45$computedHash = CustomTransactionHashUtil::computeSHA512TransactionHash(
46  $data,
47  $DEFAULT_MERCHANT_CLIENT_SECRET
48);
49
50echo $computedHash;
51


Computing Hash in Java

1import javax.crypto.Mac;
2import javax.crypto.spec.SecretKeySpec;
3import java.security.InvalidKeyException;
4import java.security.NoSuchAlgorithmException;
5import java.security.SignatureException;
6import java.util.Formatter;
7
8public class TransactionHashUtil {
9
10  private static final String HMAC_SHA512 = "HmacSHA512";
11
12  private static String toHexString(byte[] bytes) {
13      try (Formatter formatter = new Formatter()) {
14          for (byte b : bytes) {
15              formatter.format("%02x", b);
16          }
17          return formatter.toString();
18      }
19  }
20
21  /**
22   * Computes an HMAC-SHA512 hash for the given data using the merchant client secret.
23   *
24   * @param data                 The stringified JSON payload
25   * @param merchantClientSecret The merchant's client secret key
26   * @return The computed HMAC-SHA512 hash as a lowercase hex string
27   * @throws SignatureException       If the signature computation fails
28   * @throws NoSuchAlgorithmException If HmacSHA512 is not available
29   * @throws InvalidKeyException      If the provided key is invalid
30   */
31  public static String computeHMAC512TransactionHash(String data, String merchantClientSecret)
32          throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
33
34      SecretKeySpec secretKeySpec = new SecretKeySpec(merchantClientSecret.getBytes(), HMAC_SHA512);
35      Mac mac = Mac.getInstance(HMAC_SHA512);
36      mac.init(secretKeySpec);
37
38      byte[] rawHmac = mac.doFinal(data.getBytes());
39      return toHexString(rawHmac);
40  }
41}
42

Best Practices

It’s highly recommended you do the following when processing webhook notifications from us.

  1. Transaction Hash Validation: This is applicable by default on our transaction notification webhook. A hash of some properties in the request payload is computed, and you can validate this on your server by computing the same hash and comparing outputs.
  2. Whitelist Monnify's webhook IP address: To prevent requests from un-authorized origins, you can whitelist our IP address and only honor requests from this IP. Webhook notifications from Monnify will come from the following IP addresses - 35.242.133.146.
  3. Check for duplicate notifications: It’s important to keep track of all notifications you’ve received. When a new notification is received, always check that this has not been processed before giving value so as not to give double value to customers. A resend of already processed notification can happen if we do not get a 200 HTTP Status code, or in the case of a request time out.
  4. Process Complex Logic After Responding to Monnify: If your application will perform complex or time consuming logic with received notifications, this might lead to a time out between Monnify and your system, hence leading to a resend. For this reason, it’s recommended you immediately acknowledge receipt of the notification by returning a 200 HTTP Status code, and then perform your long processing activities.

Rate this page

How would you rate your experience?

Copyright © 2025 Monnify
instagramfacebookicon