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.
Webhook signature verification validates that webhook notifications are sent by Cashfree and haven’t been tampered with during transmission. This cryptographic verification protects your server from accepting malicious or forged webhook requests.
Each webhook request sent by Cashfree includes the following:
Parameter Description x-webhook-signatureHMAC SHA256 signature generated by Cashfree. x-webhook-timestampTimestamp of when the webhook was generated. Request body The actual webhook payload.
To validate the webhook, verify the signature using your webhook secret key.
Verification flow
To validate the webhook:
Capture headers and raw payload
Read x-webhook-signature from request headers.
Read x-webhook-timestamp from request headers.
Capture the raw request body.
Don’t modify, parse, or reformat the request body before verification.
Create signature data
Concatenate the timestamp and raw request body: signatureData = timestamp + rawBody
Generate HMAC SHA256 signature
Use your webhook secret key.
Apply HMAC SHA256 hashing on signatureData.
Encode signature
Encode the hash as a Base64 string.
Compare signatures
Compare the computed signature with the received signature: computed_signature == x-webhook-signature
If matched: Webhook is valid.
If not matched: Reject the request.
Sample implementations
Select your language or framework to view a sample implementation.
const express = require ( "express" );
const crypto = require ( "crypto" );
const app = express ();
// Capture raw body
app . use ( express . json ({
verify : ( req , res , buf ) => {
req . rawBody = buf . toString ();
}
}));
function verifyWebhook ( req ) {
const signature = req . headers [ "x-webhook-signature" ];
const timestamp = req . headers [ "x-webhook-timestamp" ];
const rawBody = req . rawBody ;
const secretKey = process . env . CASHFREE_WEBHOOK_SECRET ;
const computedSignature = crypto
. createHmac ( "sha256" , secretKey )
. update ( timestamp + rawBody )
. digest ( "base64" );
return computedSignature === signature ;
}
app . post ( "/webhook" , ( req , res ) => {
if (! verifyWebhook ( req )) {
return res . status ( 400 ). send ( "Invalid signature" );
}
res . send ( "Webhook received" );
});
import hmac
import hashlib
import base64
from flask import request
def verify_webhook ( secret_key ):
webhook_signature = request.headers.get( "x-webhook-signature" )
timestamp = request.headers.get( "x-webhook-timestamp" )
raw_body = request.get_data( as_text = True )
signature_data = timestamp + raw_body
dig = hmac.new(
secret_key.encode( 'utf-8' ),
msg =signature_data.encode( 'utf-8' ),
digestmod =hashlib.sha256
).digest()
computed_signature = base64.b64encode(dig).decode()
return computed_signature == webhook_signature
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"io/ioutil"
"net/http"
)
func verifyWebhook ( r * http . Request , secretKey string ) bool {
signature := r . Header . Get ( "x-webhook-signature" )
timestamp := r . Header . Get ( "x-webhook-timestamp" )
bodyBytes , _ := ioutil . ReadAll ( r . Body )
rawBody := string ( bodyBytes )
h := hmac . New ( sha256 . New , [] byte ( secretKey ))
h . Write ([] byte ( timestamp + rawBody ))
computed := base64 . StdEncoding . EncodeToString ( h . Sum ( nil ))
return computed == signature
}
<?php
function verifyWebhook ( $secretKey ) {
$rawBody = file_get_contents ( "php://input" );
$timestamp = $_SERVER [ 'HTTP_X_WEBHOOK_TIMESTAMP' ];
$signature = $_SERVER [ 'HTTP_X_WEBHOOK_SIGNATURE' ];
$computed = base64_encode (
hash_hmac ( 'sha256' , $timestamp . $rawBody , $secretKey , true )
);
return $computed === $signature ;
}
?>
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class WebhookValidator {
public static boolean verify ( String rawBody , String timestamp , String signature , String secretKey ) {
try {
String data = timestamp + rawBody;
Mac mac = Mac . getInstance ( "HmacSHA256" );
mac . init ( new SecretKeySpec ( secretKey . getBytes (), "HmacSHA256" ));
byte [] hash = mac . doFinal ( data . getBytes ());
String computed = Base64 . getEncoder (). encodeToString (hash);
return computed . equals (signature);
} catch ( Exception e ) {
return false ;
}
}
}
using System ;
using System . Security . Cryptography ;
using System . Text ;
public class WebhookValidator
{
public static bool Verify ( string rawBody , string timestamp , string signature , string secretKey )
{
var data = timestamp + rawBody ;
using ( var hmac = new HMACSHA256 ( Encoding . UTF8 . GetBytes ( secretKey )))
{
var hash = hmac . ComputeHash ( Encoding . UTF8 . GetBytes ( data ));
var computed = Convert . ToBase64String ( hash );
return computed == signature ;
}
}
}
Security requirements
Keep the following requirements in mind when implementing webhook signature verification.
Always use the raw request body for signature computation.
Don’t modify, parse, or reformat the payload before verification.
Store your webhook secret key securely. Use environment variables.
Reject webhook requests if signature mismatch occurs or required headers are missing.
Best practices
Use these practices to improve the security and reliability of your webhook implementation.
Validate timestamp to prevent replay attacks (recommended window: 5 minutes).
Log invalid webhook attempts for debugging and monitoring.
Process webhook events only after successful signature verification.
Summary
The verification process covers the following steps:
Capture the x-webhook-signature and x-webhook-timestamp headers along with the raw request body.
Concatenate the timestamp and raw body to form the signature data.
Generate an HMAC SHA256 hash using your webhook secret key.
Encode the hash as a Base64 string.
Compare the computed signature with x-webhook-signature. If they match, the webhook is valid. If they don’t match, reject the request.