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

# Webhooks Version V2

> Set up Cashfree Payouts v2 webhooks to receive HTTP callbacks for transfer events, configure retries, whitelist Cashfree IPs, and explore sample event payloads.

Webhooks are HTTP callbacks that Cashfree Payments sends to your server when specific events occur in your payout transactions. They provide real-time notifications about transfer status changes, enabling you to automate your business processes and keep your systems synchronised with transaction updates.

Version 2 webhooks offer enhanced reliability, improved payload structure, and additional event types compared to the previous version. They're essential for maintaining accurate transaction records and providing timely updates to your end users about their transfer status.

For seamless integration and security in handling your transactions, refer to the following essential guidelines:

* [Add a webhook](#add-a-webhook)
* [Webhook retries](#webhook-retries)
* [IPs to whitelist](#ips-to-whitelist)

### Add a webhook

Follow the instructions below to configure webhooks for version 2 APIs:

1. Log in to the [Merchant Dashboard](https://merchant.cashfree.com/merchants/landing).
2. Select **Payouts**.
3. Navigate to **Developers** > **Webhooks**.
4. Click **Add Webhook URL** on the *Webhooks* page.

<Frame caption="">
  <img src="https://mintcdn.com/cashfreepayments-d00050e9/vGHAFJp1ZDsFJV2e/static/images/payouts-transfers/webhooks-v1-1.png?fit=max&auto=format&n=vGHAFJp1ZDsFJV2e&q=85&s=86b30725c8c3d4660fe7a833bbc64665" width="1904" height="982" data-path="static/images/payouts-transfers/webhooks-v1-1.png" />
</Frame>

5. In the *Add Webhook* popup, enter the following information:
   * **Webhook URL**: Enter the URL where you want to receive transfer-related notifications.
   * **Select a webhook version**: Select **V2** from the dropdown menu.

<Note>
  **Webhook Version: V2**: You will receive V2 webhooks only if you select the option as described and configure the respective URL.
</Note>

6. Click **Test & Add Webhook**.
   <Frame caption="">
     <img src="https://mintcdn.com/cashfreepayments-d00050e9/vGHAFJp1ZDsFJV2e/static/images/payouts-transfers/webhooks-v1-2.png?fit=max&auto=format&n=vGHAFJp1ZDsFJV2e&q=85&s=3620568f25bfee9e7838d3ca3ba0c994" width="1904" height="982" data-path="static/images/payouts-transfers/webhooks-v1-2.png" />
   </Frame>

## Webhook signature verification code

These code snippets provide functionality to verify the authenticity of webhook requests and parse the payload data. They ensure that incoming webhook requests are from a trusted source by checking their signature and then processing the request data.

<CodeGroup>
  ```go Go theme={"dark"}
  type PayoutWebhookEvent struct {
  Type   string
  Raw    string
  Object interface{}
  }

  func PayoutVerifyWebhookSignature(signature string, rawBody string, timestamp string) (*PayoutWebhookEvent, error) {
  signatureString := timestamp + rawBody
  hmacInstance := hmac.New(sha256.New, []byte(*XClientSecret))
  hmacInstance.Write([]byte(signatureString))
  bytesData := hmacInstance.Sum(nil)
  generatedSignature := base64.StdEncoding.EncodeToString(bytesData)
  if generatedSignature == signature {
  var object interface{}
  err := json.Unmarshal([]byte(rawBody), &object)
  if err != nil {
  return nil, errors.New("something went wrong when unmarshalling raw body")
  }
  if objectAsMapInterface, ok := object.(map[string]interface{}); ok {
  if webhookType, ok := objectAsMapInterface["type"].(string); ok {
  return &PayoutWebhookEvent{Type: webhookType, Raw: rawBody, Object: object}, nil
  }
  }
  return &PayoutWebhookEvent{Type: "", Raw: rawBody, Object: object}, nil
  }
  return nil, errors.New("generated signature and received signature did not match")
  }
  ```

  ```jsx Node theme={"dark"}
  import crypto from "crypto";

  class PayoutWebhookEvent {
  	constructor(type, rawBody, object) {
  		this.type = type;
  		this.raw = rawBody;
  		this.object = object;
  	}
  }

  class Cashfree {
  	static XClientSecret;
  	static XApiVersion = "2024-01-01";

  	/**
  	 * Use this API to verify your webhook signature once you receive from Cashfree's server.
  	 * @summary Verify Webhook Signatures
  	 * @param {string} signature that is present in the header of the webhook ("x-webhook-signature")
  	 * @param {string} rawBody is the entire body sent to the server in string format
  	 * @param {string} timestamp that is present in the header of the webhook ("x-webhook-timestamp")
  	 * @throws {Error}
  	 */
  	static PayoutVerifyWebhookSignature(signature, rawBody, timestamp) {
  		const body = timestamp + rawBody;
  		const secretKey = Cashfree.XClientSecret;
  		let generatedSignature = crypto
  			.createHmac("sha256", secretKey)
  			.update(body)
  			.digest("base64");
  		if (generatedSignature === signature) {
  			let jsonObject = JSON.parse(rawBody);
  			return new PayoutWebhookEvent(jsonObject.type, rawBody, jsonObject);
  		}
  		throw new Error(
  			"Generated signature and received signature did not match."
  		);
  	}
  }
  ```
</CodeGroup>

<Note>
  **Client secret for webhooksignature**<br />
  Please ensure that the oldest active client secret is used to generate the webhook signature. Using any other client secret will lead to a signature mismatch.
</Note>

### Components

The webhook signature verification implementation uses the following key components to ensure secure processing of webhook events:

#### PayoutWebhookEvent class

This class represents the structure of a webhook event and contains the following properties:

| Property | Type   | Description                               |
| :------- | :----- | :---------------------------------------- |
| `Type`   | string | The type of the event.                    |
| `Raw`    | string | The raw JSON body of the webhook request. |
| `Object` | object | The parsed JSON object from the raw body. |

#### PayoutVerifyWebhookSignature method

This method verifies the signature of a webhook request and parses the data. Use the following parameters when calling this method:

| Parameter   | Type   | Description                                                           |
| :---------- | :----- | :-------------------------------------------------------------------- |
| `signature` | string | The HMAC signature provided in the header information of the webhook. |
| `rawBody`   | string | The raw JSON body of the request in string format.                    |
| `timestamp` | string | The timestamp provided in the header information of the webhook.      |

#### Cashfree class

This class provides the method for verifying webhook signatures and includes the following properties:

| Property        | Type   | Description                  |
| :-------------- | :----- | :--------------------------- |
| `XClientSecret` | string | Secret key.                  |
| `XAPIVersion`   | string | The API version: 2024-01-01. |

## Webhook events

Payouts webhooks enable you to receive updates about all event-driven activities originating from your account. Below is the list of payout webhooks:

| Events                   | Notifications                                                                                                                               |
| :----------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
| `TRANSFER_ACKNOWLEDGED`  | You receive this event when the transfer is successful, the amount is debited from the account, and the funds are credited to the end user. |
| `TRANSFER_SUCCESS`       | You receive this event when the transferred amount is deposited in the beneficiary's bank account.                                          |
| `TRANSFER_FAILED`        | You receive this event when the transfer attempt fails.                                                                                     |
| `TRANSFER_REVERSED`      | You receive this event when the beneficiary's bank reverses the transfer request.                                                           |
| `TRANSFER_REJECTED`      | You receive this event when Cashfree Payments rejects the transfer request.                                                                 |
| `BULK_TRANSFER_REJECTED` | You receive this event when one or more transfers in the batch transfer request are rejected.                                               |
| `BENEFICIARY_INCIDENT`   | You receive this event when there is a service disruption or incident affecting a specific beneficiary bank or payment mode.                |
| `CREDIT_CONFIRMATION`    | You receive this event when funds are credited to your account balance, providing confirmation of the credit transaction.                   |
| `LOW_BALANCE_ALERT`      | You receive this event when your account balance falls below a predefined threshold, alerting you to add funds.                             |

### Sample payload

The following examples show the JSON payload structure for each webhook event type listed above. Each payload contains event-specific data that helps you understand the transfer status and take appropriate action in your application.

<CodeGroup>
  ```json ACKNOWLEDGED theme={"dark"}
  {
  	"data": {
  		"transfer_id": "JUNOB2018",
  		"cf_transfer_id": "123456",
  		"status": "SUCCESS",
  		"status_code": "COMPLETED",
  		"status_description": "The transfer has been initiated via the partner bank successfully, hence your account is debited and the request is successfully processed by the beneficiary bank and has been credited to the end beneficiary.",
  		"beneficiary_details": {
  			"beneficiary_id": "JOHN18011",
  			"beneficiary_instrument_details": {
  				"bank_account_number": "7766671501729",
  				"bank_ifsc": "SBIN0000003"
  			}
  		},
  		"transfer_amount": 1,
  		"transfer_service_charge": 1,
  		"transfer_service_tax": 0.18,
  		"transfer_mode": "BANK",
  		"transfer_utr": "TESTR92023012200543116",
  		"fundsource_id": "CASHFREE_1",
  		"added_on": "2021-11-24T13:39:25Z",
  		"updated_on": "2021-11-24T13:40:27Z"
  	},
  	"event_time": "2024-07-25T17:43:37",
  	"type": "TRANSFER_ACKNOWLEDGED"
  }
  ```

  ```json SUCCESS theme={"dark"}
  {
  	"data": {
  		"transfer_id": "JUNOB2018",
  		"cf_transfer_id": "123456",
  		"status": "SUCCESS",
  		"status_code": "SENT_TO_BENEFICIARY",
  		"status_description": "The transfer has been initiated via the partner bank successfully. The request is waiting to be processed at the beneficiary bank to do the credit to the end beneficiary.",
  		"beneficiary_details": {
  			"beneficiary_id": "JOHN18011",
  			"beneficiary_instrument_details": {
  				"bank_account_number": "7766671501729",
  				"bank_ifsc": "SBIN0000003"
  			}
  		},
  		"transfer_amount": 1,
  		"transfer_service_charge": 1,
  		"transfer_service_tax": 0.18,
  		"transfer_mode": "BANK",
  		"transfer_utr": "TESTR92023012200543116",
  		"fundsource_id": "CASHFREE_1",
  		"added_on": "2021-11-24T13:39:25Z",
  		"updated_on": "2021-11-24T13:40:27Z"
  	},
  	"event_time": "2024-07-25T17:43:37",
  	"type": "TRANSFER_SUCCESS"
  }
  ```

  ```json FAILED theme={"dark"}
  {
  	"data": {
  		"transfer_id": "JUNOB2018",
  		"cf_transfer_id": "123456",
  		"status": "FAILED",
  		"status_code": "IMPS_MODE_FAIL",
  		"status_description": "The transfer has failed because the beneficiary account doesnot support IMPS transfers. This rejection is done by the partner bank for the specific beneficiary account. You can try NEFT or other channels to do the disbursals.",
  		"beneficiary_details": {
  			"beneficiary_id": "JOHN18011",
  			"beneficiary_instrument_details": {
  				"bank_account_number": "7766671501729",
  				"bank_ifsc": "SBIN0000003"
  			}
  		},
  		"transfer_amount": 1,
  		"transfer_service_charge": 1,
  		"transfer_service_tax": 0.18,
  		"transfer_mode": "BANK",
  		"transfer_utr": "TESTR92023012200543116",
  		"fundsource_id": "CASHFREE_1",
  		"added_on": "2021-11-24T13:39:25Z",
  		"updated_on": "2021-11-24T13:40:27Z"
  	},
  	"event_time": "2024-07-25T17:43:37",
  	"type": "TRANSFER_FAILED"
  }
  ```

  ```json REVERSED theme={"dark"}
  {
  	"data": {
  		"transfer_id": "JUNOB2018",
  		"cf_transfer_id": "123456",
  		"status": "REVERSED",
  		"status_code": "INVALID_ACCOUNT_FAIL",
  		"status_description": "The transfer has been reversed by the beneficiary bank because the Account Number of the beneficiary is invalid. After correcting the account number, you can reinitiate the transfer via Cashfree so that the transfer can be reattempted again by Cashfree with the partner bank(s).",
  		"beneficiary_details": {
  			"beneficiary_id": "JOHN18011",
  			"beneficiary_instrument_details": {
  				"bank_account_number": "7766671501729",
  				"bank_ifsc": "SBIN0000003"
  			}
  		},
  		"transfer_amount": 1,
  		"transfer_mode": "BANK",
  		"fundsource_id": "CASHFREE_1",
  		"added_on": "2021-11-24T13:39:25Z",
  		"updated_on": "2021-11-24T13:40:27Z"
  	},
  	"event_time": "2024-07-25T17:43:37",
  	"type": "TRANSFER_REVERSED"
  }
  ```

  ```json REJECTED theme={"dark"}
  {
  	"data": {
  		"transfer_id": "JUNOB2018",
  		"cf_transfer_id": "123456",
  		"status": "REJECTED",
  		"status_code": "INVALID_MODE_FOR_PYID",
  		"status_description": "The transfer has been rejected because the fundsource does not support this mode of transfer. You should get this mode activated on the fundsource by contacting Cashfree, and then initiate a new transfer request.",
  		"beneficiary_details": {
  			"beneficiary_id": "JOHN18011"
  		},
  		"transfer_amount": 1,
  		"transfer_mode": "BANK",
  		"fundsource_id": "CASHFREE_1",
  		"added_on": "2021-11-24T13:39:25Z",
  		"updated_on": "2021-11-24T13:40:27Z"
  	},
  	"event_time": "2024-07-25T17:43:37",
  	"type": "TRANSFER_REJECTED"
  }
  ```

  ```json BULK_TRANSFER_REJECTED theme={"dark"}
  {
  	"data": {
  		"batch_transfer_id": "test_batch_transfer_id",
  		"cf_batch_transfer_id": "123456",
  		"status": "REJECTED"
  	},
  	"event_time": "2024-07-25T17:43:37",
  	"type": "BULK_TRANSFER_REJECTED"
  }
  ```

  ```json LOW_BALANCE theme={"dark"}
  {
    "data" : {
      "current_balance": "8.53",
      "fundsource_id": "astring"
    },
    "type": "LOW_BALANCE_ALERT",
    "event_time": "2024-07-25T17:43:37"
  }
  ```

  ```json CREDIT_CONFIRMATION theme={"dark"}
  {
    "data" : {
      "ledger_balance": "8.53",
      "utr": "ledgerEntryUTR654321",
      "amount": "10.50",
      "fundsource_id": "astring"
    },
    "type": "CREDIT_CONFIRMATION",
    "event_time": "2024-07-25T17:43:37"
  }

  ```

  ```json BENEFICIARY_INCIDENT theme={"dark"}
  {
    "data" : {
      "bene_entity": "BANK",
      "id": 789,
      "mode": "UPI",
      "started_at": "yyyy-MM-dd HH:mm:ss",
      "status": "ACTIVE",
      "is_scheduled": true,
      "severity": "High",
      "entity_name": "name",
      "entity_code": "code",
      "resolved_at": "yyyy-MM-dd HH:mm:ss"
    },
    "event_time": "2024-07-25T17:43:37",
    "type": "BENEFICIARY_INCIDENT"
  }
  ```
</CodeGroup>

### Parameters

Find the parameters and their descriptions for the events `TRANSFER_ACKNOWLEDGED`, `TRANSFER_SUCCESS`, `TRANSFER_FAILED`, `TRANSFER_REVERSED`, and `TRANSFER_REJECTED` below:

| Parameter                        | Description                                                        |
| :------------------------------- | :----------------------------------------------------------------- |
| `transfer_id`                    | The unique ID you created to identify the transfer request.        |
| `cf_transfer_id`                 | The unique ID created by Cashfree Payments for reference purposes. |
| `status`                         | The status of the transfer.                                        |
| `status_code`                    | The specific status of the transfer.                               |
| `status_description`             | The detailed explanation of the transfer status.                   |
| `beneficiary_details`            | Information about the beneficiary.                                 |
| `beneficiary_id`                 | The unique ID to identify the beneficiary.                         |
| `beneficiary_instrument_details` | The account information of the beneficiary.                        |
| `bank_account_number`            | The bank account number of the beneficiary.                        |
| `bank_ifsc`                      | The IFSC information of the bank.                                  |
| `transfer_amount`                | The transfer amount.                                               |
| `transfer_service_charge`        | The service charge applied for the transfer amount.                |
| `transfer_service_tax`           | The taxable amount for the service charge.                         |
| `transfer_mode`                  | The transfer mode.                                                 |
| `transfer_utr`                   | The unique transaction reference number.                           |
| `fundsource_id`                  | The unique ID to identify the fund source.                         |
| `added_on`                       | The date and time of the addition.                                 |
| `updated_on`                     | The date and time of the update.                                   |
| `event_time`                     | The date and time of the webhook event initiation.                 |
| `type`                           | The event type.                                                    |

Find the parameters and their descriptions for the event `BULK_TRANSFER_REJECTED` below:

| Parameter              | Description                                                        |
| :--------------------- | :----------------------------------------------------------------- |
| `batch_transfer_id`    | The unique ID you created to identify the batch transfer request.  |
| `cf_batch_transfer_id` | The unique ID created by Cashfree Payments for reference purposes. |
| `status`               | The status of the batch transfer request.                          |
| `event_time`           | The date and time of the webhook event initiation.                 |
| `type`                 | The event type.                                                    |

<Note>
  A transfer is considered successful only when both the status is `SUCCESS` and the status code is `COMPLETED`.
</Note>

### Webhook retries

Cashfree Payments webhooks service does its best to deliver events to your webhook endpoint. It's best practice for your application to respond to the callback. Our webhook service may send many payloads to a single endpoint in quick succession. You will need to build an application and configure your server to receive the response we send when events get triggered during the payout process.

Your server should return a 200 HTTP status code to acknowledge that you received the webhook without any issues. Any other information you return in the request headers or request body is ignored. Any response code outside the 200 range, including 3xx codes, indicates that you didn't receive the webhook.

When Cashfree Payments doesn't receive the acknowledgement for any reason, we retry to establish communication at regular intervals. If we don't receive the response after several attempts, we gradually decrease the rate of retries. Based on this count, the service is disabled if it fails more than five times.

If you don't receive notifications from Cashfree Payments as expected, please fill out the [Support Form](https://merchant.cashfree.com/merchants/landing?env=prod\&raise_issue=1).

### IPs to whitelist

When you decide to consume the webhooks, first, you need to verify whether your systems need IP whitelisting to be done at your end or not. Accordingly, you can whitelist the below IPs of Cashfree:

| UAT           |
| :------------ |
| 52.66.25.127  |
| 15.206.45.168 |

| Prod          |
| :------------ |
| 52.66.101.190 |
| 3.109.102.144 |
| 18.60.134.245 |
| 18.60.183.142 |

| Port          |
| :------------ |
| 443 (secured) |

## FAQs

<AccordionGroup>
  <Accordion title="Can I subscribe to webhooks V2 if I use Payouts APIs as V1 and V1.2?">
    Yes, you can subscribe to **Webhooks V2** even if you're currently using **Payout APIs v1 and v1.2**.
  </Accordion>

  <Accordion title="Can I utilise webhooks V1 whilst using Payouts APIs V2?">
    Yes, you can typically subscribe to **Webhooks V1** even if you're using **Payout APIs V2**.
  </Accordion>
</AccordionGroup>
