Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
As a fintech, you will be performing the following actions to
Div
classdeveloper-cookbook-inner-page-title
HTML Table
classtagline-page-title
Table Row (tr)
Table Cell (td)
classtitle-text

Learn configure a webhook and receive event notifications from Fusion

Using Fusion webhook APIs, you can set up a webhook against the available Fusion event types. In this tutorial, you will learn about how to set up a webhook that can be used to receive a payment an event notification about important business process flows.

Info

For the complete list of Webhook more information on webhook APIs, see  Core API Reference.

Configure a

Webhook

webhook

Note

Keep a webhook endpoint URL ready that can receive JSON objects and support basic HTTP authentication. Share this endpoint with Zeta. Zeta will register the webhook endpoint in Fusion platform and share a secret token with you to validate the incoming webhook messages.

Select

a Payment

an Event

Before creating a webhook, let's find out Fusion topics and events that are available for you to configure a webhook. See Supported Fusion Events for a list of topics/events that you can subscribe to.

Add a webhook

Set up your webhook to handle incoming payment event messages using /payment/events/{eventName}/subscribe endpoint and pass the event object, eventName, in the path parameter that you obtained from Select a Payment Event step. Specify a webhook endpoint, callbackUrl in the registerWebhookSubscription endpoint. Specify the event details in the body parameter. 

To add a webhook against a payment an event, use the following endpoint:

Status
colourGreen
titlepost

api/v1/ifi/{ifiID}/payment/events/{eventName}/subscribe
registerWebhookSubscription

Input parameters

  • subscriptionID: Required. Unique identifier of the event subscription.
  • topic: Required. Fintech-specific object to which the event is emitted from a business logic.
  • webhookURL: Required. Webhook endpoint to handle incoming webhook messages.
  • secret: Required. Secret token to validate the incoming webhook message. Zeta will share a secret token

Example

Div
classcustomtabs
Div
classtabsmenu
Div
classtabsmenu_1

Request

Div
classtabsmenu_2

Response

Div
classtabscontent
Div
classtabpage_1
Code Block
languagejs
themeMidnight
titlecURL sample
collapsetrue
curl -X POST \
  https://fusion.preprod.zeta.in/api/v1/ifi/140827/payment/event/PAYMENT_REQUESTED/subscriberegisterWebhookSubscription \
  -H 'authorization: {{auth-token}} \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
  "subscriptionID": "aki98dfsb-asdnkj3eoqh-006kgur",
  "callbackUrltopic": "http://customer-prod-api.in/callback"
    }
}_tenant_140827_RESOURCE",
  "webhookURL": "https://yoursample.com/t/gffrp-1595524776/post",
  "secret": "Yjc3MDkxN3YYOWYzZmIzMjNkMjg1mQuC"
}'
Div
classtabpage_2

N/A

Test a Webhook

After you've subscribed for
Code Block
languagejs
themeMidnight
titlecURL sample
collapsetrue
200 OK
401 Unauthorized
403 Forbidden
404 Not Found

Test a webhook

After you have subscribed for an event notification (lets say, a payment and A2A transfer event notification) , simulate an Ecom, ATM or POS transaction and check the webhook endpoint for any possible notification. The webhook endpoint is the callbackUrlwebhookURL you've configured in the previous step against a payment event/topic (eventNametopic). If you receive a webhook message, proceed to the next step to verify that the incoming message delivered from a secured Fusion endpoint.

Note

Contact Zeta Support to simulate and test a payment webhook.

Div
classcustomtabs
Div
classtabsmenu
Div
classtabsmenu_1

Payment Event

Div
classtabsmenu_2

A2A Transfer Event

Div
classtabscontent
Div
classtabpage_1

A new sample payment event would look something like this after the webhook configuration and subscription. Note the topicnameeventIDsourceorigin and data objects in the payload below:

Code Block
languagejs
themeMidnight
titlePayment event received after configuring a webhook
collapsetrue
{
  "topic": "_tenant_140827_RESOURCE",
  "name": "RESOURCE_PAYMENT_CREATED",
  "eventID": "fc529204-126e-4b37-8308-02bdd1a29b52",
  "source": {
    "uri": "resource://140827/0c97e84f-999d-4fdf-a53f-24cb99b11e76/870544000001",
    "tags": [
      "tag://VBO/ABC001",
      "tag://VBO/ABC001"
    ],
    "state": "PAYMENT_REQUESTED"
  },
  "origin": {
    "instance": "instance://default/payment/870544",
    "time": 1582108024106,
    "flowID": "4807977e-fe36-4f03-be80-3b67dfbf23a9"
  },
  "data": {
    "paymentID": 870544000001,
    "currentState": "PAYMENT_REQUESTED",
    "stateTransitions": {
      "PAYMENT_REQUESTED": {
        "time": 1582108023741
      }
    },
    "payerInfo": {
      "resourceID": "0c97e84f-999d-4fdf-a53f-24cb99b11e76",
      "formFactorURI": "card://ff936322-287f-43e4-9497-a86d94bd97a9",
      "targetURI": "account://6b2dfb83-9276-422c-8781-07eda71fc261",
      "type": "RESOURCE"
    },
    "payeeInfo": {
      "type": "EXTERNAL_BUSINESS",
      "name": "TEST MERCHANT",
      "location": "MUMBAI"
    },
    "receipt": [],
    "attributes": {
      "super-card.trans-id": "M00001_T00001_111111_022030_486837818528_200219102702",
      "super-card.rrn": "486837818528",
      "super-card.ifi": "140827",
      "super-card.card-6x4": "508645-xxxxxx-0289",
      "super-card.merchant-country": "IN",
      "journal.voucherCode": "RUPAY-508645_ECOM_AUTH",
      "super-card.merchant-city": "MUMBAI",
      "super-card.acquirer": "111111",
      "super-card.acs-txnId": "028852720888773631103971827607",
      "super-card.merchant-lat": "18.975",
      "super-card.card-bin": "508645",
      "credentials.signatory": "10276@zetauser.zeta.in/1",
      "super-card.stan": "022030",
      "super-card.mid": "M00001",
      "super-card.tid": "T00001",
      "super-card.mcc": "5411",
      "super-card.merchant-lon": "72.825833",
      "super-card.txn-type": "ECOM",
      "super-card.otp-enter-mode": "manual",
      "supercard-card.authentication-type": "DYNAMIC_PIN",
      "super-card.merchant-name": "TEST MERCHANT",
      "super-card.card-id": "resource://0c97e84f-999d-4fdf-a53f-24cb99b11e76_ff936322-287f-43e4-9497-a86d94bd97a9",
      "super-card.ink": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36",
      "super-card.init-time": "200219102702"
    }
  },
  "publisher": {
    "appDomain": "services.fusion",
    "serviceName": "payment",
    "nodeId": "870544"
  }
}
Div
classtabpage_2

A new A2A transfer event would look something like this after the webhook configuration and subscription. Note the topicnameeventIDsourceorigin and data objects in the payload below:

Code Block
languagejs
themeMidnight
titleA2A transfer event received after creating a payment transfer
collapsetrue
{
  "data": {
    "topic": "_tenant_140827_a2aTransferA2ATransfer",
    "name": "TRANSFER_CREATED",
    "eventID": "f62fa71f-7cc0-478d-b896-abf74e675e0f",
    "source": {
      "uri": "a2aTransfer://140827/c8b0ffbe-93f6-46a1-86e9-bb3213d42a38?publishingApp=fusion",
      "tags": [
        "tag://vbo-id/4fa18593-d2d9-4bf3-bea7-7f6deb9f2ca4?publishingApp=fusion"
      ],
      "state": "COMPLETED"
    },
    "origin": {
      "instance": "instance://default/fusion/295411",
      "time": 1590736346458,
      "flowID": "64e276bc-3908-43f7-978a-b58155da5127"
    },
    "data": {
      "ifiId": 140827,
      "transferRequest": {
        "requestID": "c8b0ffbe-93f6-46a1-86e9-bb3213d42a38",
        "currency": "INR",
        "amount": 1000000,
        "transferCode": "ATLAS_P2M_AUTH",
        "debitAccountID": "3867f3ac-fa4b-4f7c-859c-41bbeb586c45",
        "creditAccountID": "0e7381cc-a1f3-4af7-9a50-f120be76b1b8",
        "transferTime": 12324254832342,
        "remarks": "TEST",
        "attributes": {}
      },
      "transferResponse": {
        "requestID": "c8b0ffbe-93f6-46a1-86e9-bb3213d42a38",
        "transferID": "20200529071226316_28033_c8b0ffbe-93f6-46a1-86e9-bb3213d42a38",
        "status": "SUCCESS"
      }
    },
    "publisher": {
      "appDomain": "services.olympus",
      "serviceName": "fusion",
      "nodeId": "295411"
    },
    "emitterType": "EVENT"
  },
  "attributes": {
    "topic": "_tenant_140827_a2aTransfer"
  }
}

Validate a

Webhook

webhook

Note

Ensure that you have already shared the webhook endpoint with Zeta. Zeta will register the webhook endpoint in Fusion platform.

You must verify every incoming event to ensure the messages are delivering from a secured Fusion endpoint. Zeta will share a secret token (used in above API call) with you to verify the authenticity of the message. Using the secret token, you can generate an HMAC (Hash-based Message Authentication Code) signature to match with the X-Zeta-HMAC that is passed in the header along with the event message. 

To validate a webhook

You can use the ZetaHmacVerificationUtil class to validate the webhook:

Code Block
languagejava
themeMidnight
titleZetaHmacVerificationUtil (use class as code)
collapsetrue
package com.company.mypackage;

import static com.google.common.hash.Hashing.sha256;
import static java.nio.charset.StandardCharsets.UTF_8;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.annotation.Nonnull;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class ZetaHmacVerificationUtil {
  private static final String HMAC_SHA_512 = "HmacSHA512";

  /**
   * @param data - the raw bytes extracted from the received event body 
   * @param secretBase64 - the secret shared by Zeta, Base64 encoded
   * @param nonce - the Nonce value from the HTTP header with the key X-Zeta-Nonce
   * @param incomingZetaHmac - the HMAC value extracted from the HTTP header with the key X-Zeta-HMAC
   * @return - true if the incoming HMAC is equal to the Zeta-computed HMAC, false otherwise
   */
  public static boolean verifyZetaHmac(
      @Nonnull byte[] data,
      @Nonnull String secretBase64,
      @Nonnull String nonce,
      @Nonnull String incomingZetaHmac) {
    return incomingZetaHmac.equals(computeZetaHmac(data, secretBase64, nonce));
  }

  /**
   * @param data - the raw bytes extracted from the received event body
   * @param secretBase64 - the secret shared by Zeta, Base64 encoded
   * @param nonce - the Nonce value from the HTTP header with the key X-Zeta-Nonce
   * @return - the Zeta-computed HMAC
   */
  public static String computeZetaHmac(byte[] data, String secretBase64, String nonce) {
    byte[] nonceBytes = nonce.getBytes(UTF_8);
    byte[] hmacDataWithNonce = computeHMAC512(data, hashSha256(nonceBytes));
    byte[] secretBytes = base64Decode(secretBase64.getBytes(UTF_8));
    return new String(base64Encode(computeHMAC512(hmacDataWithNonce, secretBytes)));
  }

  private static byte[] computeHMAC512(byte[] data, byte[] secret) {
    try {
      final Mac sha512_HMAC = Mac.getInstance(HMAC_SHA_512);
      final SecretKeySpec keySpec = new SecretKeySpec(secret, HMAC_SHA_512);
      sha512_HMAC.init(keySpec);
      return sha512_HMAC.doFinal(data);
    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
      throw new RuntimeException("FAILED_TO_COMPUTE_HMAC");
    }
  }

  private static byte[] hashSha256(byte[] toHash) {
    byte[] hash = new byte[32];
    sha256().hashBytes(toHash)
        .writeBytesTo(hash, 0, 32);
    return hash;
  }

  private static byte[] base64Decode(byte[] bytes) {
    return Base64.getDecoder().decode(bytes);
  }

  private static byte[] base64Encode(byte[] bytes) {
    return Base64.getEncoder().encode(bytes);
  }
}
  1.   Extract the raw bytes from the received event body
  2.   Extract the Nonce value from the HTTP header with the key X-Zeta-Nonce
  3.   Extract the HMAC value from the HTTP header with the key X-Zeta-HMAC
  4.   Invoke the verifyZetaHmac function of the ZetaHmacVerificationUtil class, with the arguments data (from step 1), base64EncodedSecret (shared by Zeta), nonce (from step 2), hmac (from step 3). The method returns true if the incoming HMAC is equal to the Zeta-computed HMAC, and false otherwise. If the method returns true, you can consider the event message is valid and sent over secured Fusion connection. If it returns false, reject the message and report to Zeta for further analysis.
  5.   Alternatively, you can invoke ZetaHmacVerificationUtil#computeZetaHmac with the data from steps 1 and 2, along with the secret token shared by Zeta, to generate the HMAC on your own. Compare the generated HMAC with the extracted HMAC (from step 3). If both are identical, the message is valid and authentic.
Note

Contact Zeta Support to obtain the secret token or any help to validate a payment webhook.

Related articles

HTML Table
classdeveloper-cookbook-next-steps
Table Row (tr)
Table Cell (td)
classnext-steps-table-content
About

Fusion Events

Learn about supported Fusion events.

Button Hyperlink
titlebutton
typestandard
classhyperlink-overlay
urlFusion Events

Table Cell (td)
classnext-steps-table-content

Webhook APIs

Learn more about webhook APIs

Button Hyperlink
titlebutton
typestandard
classhyperlink-overlay
urlWebhook APIsPayment

Table Cell (td)
classnext-steps-table-content

Payment Lifecycle

Know about various payment events and its lifecycle.

Button Hyperlink
titlebutton
typestandard
classhyperlink-overlay
urlPayment Lifecycle

Panel
Div
classalignLeftIcon

On this page:

Table of Contents
maxLevel1
Table of Contents
minLevel4
classhide-schema

Div
classhelp-box

Need Help?

Contact us Drop a mail at fusion-support@zeta.tech or call us on 080-6690 5995.