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

> Set up Cashfree Reverse Penny Drop webhooks to receive notifications when customer-initiated UPI or netbanking bank verifications complete.

Webhooks are event-based notifications that are received when a specific event related to the reverse penny drop verification occurs.

<Warning>
  In rare cases, such as network retries, read timeouts, processing delays, or delivery failures, the same webhook might be sent more than once for the same event. To prevent unintended side effects, implement idempotency in your webhook handler to handle duplicate deliveries.
</Warning>

## Add webhooks

Add your webhook URL in our system for us to deliver webhook events.

Follow the instructions below to configure the webhook URL. Ensure to provide the publicly accessible HTTPS URL to your webhook endpoint.

1. Log in to the **[Merchant Dashboard](https://merchant.cashfree.com/merchants/)** and click **Developers**.
2. Click **Webhooks** listed under the **Secure ID** card.
3. Click **Add Webhook URL** in the **Webhook** screen.
4. In the **Add Webhook** popup, fill in the following information:
   * **Webhook URL**: Enter the URL in this field.
5. Click **Test & Add Webhook**.

<Frame caption="Add Webhook">
  <img src="https://mintcdn.com/cashfreepayments-d00050e9/iGW1Vcgx_yo5v_1g/static/secure-id/webhook.png?fit=max&auto=format&n=iGW1Vcgx_yo5v_1g&q=85&s=d8662cc06a8874021806a0119209d58f" width="3424" height="1796" data-path="static/secure-id/webhook.png" />
</Frame>

## Webhook event

| Event                                     | Description                                       |
| :---------------------------------------- | :------------------------------------------------ |
| RPD\_BANK\_ACCOUNT\_VERIFICATION\_SUCCESS | The reverse penny drop verification is a success. |
| RPD\_BANK\_ACCOUNT\_VERIFICATION\_EXPIRED | The reverse penny drop verification expired.      |
| RPD\_BANK\_ACCOUNT\_VERIFICATION\_FAILURE | The reverse penny drop verification is a failure. |

The following events are triggered at different stages of the reverse penny drop verification process:

<AccordionGroup>
  <Accordion title="RPD_BANK_ACCOUNT_VERIFICATION_SUCCESS">
    ```json theme={"dark"}
    {
       "signature":"signature",    
       "event_type":"RPD_BANK_ACCOUNT_VERIFICATION_SUCCESS",    
       "event_time":"2023-07-19 10:46:16",
       "version":"v1",
       "data":{
            "bank_account":"026291800001191", 
            "ifsc":"YESB0000262", 
            "upi": "success@upi",
            "name_at_bank":"BHARATHTEST GKUMARUT", 
            "verification_id":"91", 
            "ref_id":"49", 
            "utr":"49" ,
            "status":"SUCCESS", 
            "name_match_score":"", 
            "name_match_result":"", 
            "added_on":"2023-07-14 17:29:50", 
            "processed_on":"2023-07-14 17:30:50",              
            "penny_collected_on":"2023-07-14 17:30:50",
            "reversal_status": "PENDING",
            "account_type": "SAVINGS"
        }
    }
    ```
  </Accordion>

  <Accordion title="RPD_BANK_ACCOUNT_VERIFICATION_EXPIRED">
    ```json theme={"dark"}
    {
       "signature":"signature",    
       "event_type":"RPD_BANK_ACCOUNT_VERIFICATION_EXPIRED",    
       "event_time":"2023-07-19 10:46:16",
       "version":"v1",
       "data":{
            "bank_account":"", 
            "ifsc":"", 
            "upi": "",
            "name_at_bank":"", 
            "verification_id":"91", 
            "ref_id":"49", 
            "utr":"" ,
            "status":"EXPIRED", 
            "name_match_score":"", 
            "name_match_result":"", 
            "added_on":"2023-07-14 17:29:50", 
            "processed_on":"2023-07-14 17:30:50",           
            "penny_collected_on":""
        }
    }
    ```
  </Accordion>

  <Accordion title="RPD_BANK_ACCOUNT_VERIFICATION_FAILURE">
    ```json theme={"dark"}
    {
       "signature":"signature",    
       "event_type":"RPD_BANK_ACCOUNT_VERIFICATION_FAILURE",    
       "event_time":"2023-07-19 10:46:16",
       "version":"v1",
       "data":{
            "bank_account":"", 
            "ifsc":"", 
            "upi": "",
            "name_at_bank":"", 
            "verification_id":"91", 
            "ref_id":"49", 
            "utr":"" ,
            "status":"FAILURE", 
            "name_match_score":"", 
            "name_match_result":"", 
            "added_on":"2023-07-14 17:29:50", 
            "processed_on":"2023-07-14 17:30:50",          
            "penny_collected_on":""
        }
    }
    ```
  </Accordion>
</AccordionGroup>

## Webhook payload fields

The webhook payload contains important metadata in its top-level fields.

| Field        | Type     | Description                                                                                    |
| ------------ | -------- | ---------------------------------------------------------------------------------------------- |
| `signature`  | `string` | A Base64-encoded HMAC-SHA256 signature of the payload, generated using a shared client secret. |
| `event_type` | `string` | Indicates the type of event that triggered the webhook.                                        |
| `event_time` | `string` | The UTC timestamp of when the event occurred, formatted in ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`).  |
| `version`    | `string` | Indicates the webhook format being used. Default version is "v1".                              |
| `data`       | `object` | Contains event-specific details related to this feature.                                       |

## Signature Verification

Verifying the signature is mandatory before processing any response. It helps authenticate that the webhook is from Cashfree Payments.

Follow the steps to verify the signature:

1. Sort the array based on keys.
2. Concatenate all the values in this array and the resultant is the post data (**postData**).
3. Encrypt the `postData` with SHA-256 and Base64-encode it.
4. Verify that the calculated signature matches the signature received.
5. Continue processing only if the signatures match. Otherwise, discard the request.
6. Ensure that the `clientSecret` you use belongs to the oldest active key pair.

For example, from the webhook received, extract the data and pass it to generate HMAC function:

```
{bank_account=026291800001191, ifsc=YESB0000262, upi=, name_at_bank=John Doe,
verification_id=fadsfdsf, ref_id=332, utr=332, status=SUCCESS,
added_on=2023-09-06T07:48:53+05:30, processed_on=2023-09-06 07:49:03,
penny_collected_on=2023-09-06 07:48:53}
```

```Text Java code - for reference theme={"dark"}
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Map;
import java.util.TreeMap;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;

public class ComputedSignature {
public static String generateHMAC(String clientSecret, String data) {
        String hash = null;
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            Map<String, Object> jsonMap = objectMapper.readValue(data, new TypeReference<Map<String, Object>>() {
            });
            Map<String, Object> sortedMap = new TreeMap<>(jsonMap);

            // sort the map based on keys
            String postDataString = "";

            for (Map.Entry<String, Object> entry : sortedMap.entrySet()) {
                postDataString = postDataString + entry.getValue();
            }

            // encode the post data on sha256
            Mac sha256HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKey = new SecretKeySpec(clientSecret.getBytes(), "HmacSHA256");
            sha256HMAC.init(secretKey);

            hash = Base64.encodeBase64String(sha256HMAC.doFinal(postDataString.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();

        }
        return hash;
    }
}

```

## IPs to whitelist

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

| Sandbox       |
| :------------ |
| 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) |
