Webhooks are server callbacks to your server from Cashfree Payments.
Webhooks are event-based notifications that are received when a specific event related to the reverse penny drop verification occurs.
Webhook Event
Event | Description |
---|---|
RPD_BANK_ACCOUNT_VERIFICATION_SUCCESS | The reverse penny drop verification is a success. |
{
"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": "",
"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-18T16:27:10+05:30",
"processed_on":"2023-07-19 10:46:16", "penny_collected_on":"2022-10-27 12:40:09.530"
}
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:
- Sort the array based on keys.
- Concatenate all the values in this array and the resultant is the post data (postData).
- postData needs to be encrypted using SHA-256 and then base64 encoded.
- Verify if both the signature calculated and the signature received match.
- Proceed further only if the signatures match. If not, discard the request.
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}
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;
}
}
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;
}
}