Vendor Settlement Webhooks

Configure vendor settlement webhooks to receive automated notifications when vendor settlements are initiated, successfully processed, failed, or reversed.

The webhook notifications are sent on all the URLs added and enabled in the settlement webhook. Merchants can add new URLs and enable or disable existing URLs for settlement webhook at any time and it will reflect instantaneously.

The table below lists the webhook events available for vendor settlements.

Webhook EventDescription
VENDOR_SETTLEMENT_INITIATEDThis webhook will be triggered when a vendor settlement is initiated.
VENDOR_SETTLEMENT_SUCCESSThis webhook will be triggered when a vendor settlement is successful.
VENDOR_SETTLEMENT_FAILEDThis webhook will be triggered when a vendor settlement has failed.
VENDOR_SETTLEMENT_REVERSEDThis webhook will be triggered when a vendor settlement has been reversed.

Vendor Settlement Initiated

SETTLEMENT_INITIATED webhook is triggered when a settlement has been initiated by Cashfree Payments.


{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 10,
            "payment_amount": null,
            "payment_from": "2022-05-26",
            "payment_till": "2022-05-26",
            "reason": null,
            "service_charge": 0.05,
            "service_tax": 0.01,
            "settled_on": "2022-05-26T15: 06: 14+05: 30",
            "settled_orders_count": null,
            "settlement_amount": 10,
            "settlement_id": 6151,
            "settlement_initiated_on": "2022-05-26T15: 06: 09+05: 30",
            "settlement_type": null,
            "status": "CREATED",
            "utr": null,
            "vendor_id": IS_1hour_Upi,
            "vendor_transaction_amount": 10
        },
        "event_time": "2022-05-26T15:06:15+05:30",
        "type": "VENDOR_SETTLEMENT_INITIATED"
    }
}

Vendor Settlement Success

//Standard Settlement

{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 50,
            "payment_amount": null,
            "payment_from": "2022-04-01",
            "payment_till": "2022-04-01",
            "reason": null,
            "service_charge": 0.25,
            "service_tax": 0.05,
            "settled_on": "2022-04-01T15:03:31+05:30",
            "settled_orders_count": null,
            "settlement_amount": 50,
            "settlement_id": 3598,
            "settlement_initiated_on": "2022-04-01T13:51:00+05:30",
            "settlement_type": "STANDARD",
            "status": "SUCCESS",
            "utr": 98756789343,
            "vendor_id": IS_1hour_Upi,
            "vendor_transaction_amount": 50
        },
        "event_time": "2022-04-01T16:47:12+05:30",
        "type": "VENDOR_SETTLEMENT_SUCCESS"
    }
}
//Instant Settlement

{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 50,
            "payment_amount": null,
            "payment_from": "2022-04-01",
            "payment_till": "2022-04-01",
            "reason": null,
            "service_charge": 0.25,
            "service_tax": 0.05,
            "settled_on": "2022-04-01T15:03:31+05:30",
            "settled_orders_count": null,
            "settlement_amount": 50,
            "settlement_id": 3598,
            "settlement_initiated_on": "2022-04-01T13:51:00+05:30",
            "settlement_type": "INSTANT",
            "status": "SUCCESS",
            "utr": 98756789343,
            "vendor_id": 46696,
            "vendor_transaction_amount": 50
        },
        "event_time": "2022-04-01T16:47:12+05:30",
        "type": "VENDOR_SETTLEMENT_SUCCESS"
    }
}
//On-Demand Settlement

{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 50,
            "payment_amount": null,
            "payment_from": "2022-04-01",
            "payment_till": "2022-04-01",
            "reason": null,
            "service_charge": 0.25,
            "service_tax": 0.05,
            "settled_on": "2022-04-01T15:03:31+05:30",
            "settled_orders_count": null,
            "settlement_amount": 50,
            "settlement_id": 3598,
            "settlement_initiated_on": "2022-04-01T13:51:00+05:30",
            "settlement_type": "On-demand",
            "status": "SUCCESS",
            "utr": 98756789343,
            "vendor_id": 46696,
            "vendor_transaction_amount": 50
        },
        "event_time": "2022-04-01T16:47:12+05:30",
        "type": "VENDOR_SETTLEMENT_SUCCESS"
    }
}

Vendor Settlement Failed

//Standard Settlement

{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 10,
            "payment_amount": null,
            "payment_from": "2022-05-26",
            "payment_till": "2022-05-26",
            "reason": null,
            "service_charge": 0.05,
            "service_tax": 0.01,
            "settled_on": "2022-05-26T15: 06: 14+05: 30",
            "settled_orders_count": null,
            "settlement_amount": 10,
            "settlement_id": 6151,
            "settlement_initiated_on": "2022-05-26T15: 06: 09+05: 30",
            "settlement_type": "STANDARD",
            "status": "FAILED",
            "utr": null,
            "vendor_id": IS_1hour_Upi,
            "vendor_transaction_amount": 10
        },
        "event_time": "2022-05-26T15:06:15+05:30",
        "type": "VENDOR_SETTLEMENT_FAILED"
    }
}
//Instant Settlement

{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 10,
            "payment_amount": null,
            "payment_from": "2022-05-26",
            "payment_till": "2022-05-26",
            "reason": null,
            "service_charge": 0.05,
            "service_tax": 0.01,
            "settled_on": "2022-05-26T15: 06: 14+05: 30",
            "settled_orders_count": null,
            "settlement_amount": 10,
            "settlement_id": 6151,
            "settlement_initiated_on": "2022-05-26T15: 06: 09+05: 30",
            "settlement_type": "INSTANT",
            "status": "FAILED",
            "utr": null,
            "vendor_id": 46695,
            "vendor_transaction_amount": 10
        },
        "event_time": "2022-05-26T15:06:15+05:30",
        "type": "VENDOR_SETTLEMENT_FAILED"
    }
}
//On-demand Settlement

{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 10,
            "payment_amount": null,
            "payment_from": "2022-05-26",
            "payment_till": "2022-05-26",
            "reason": null,
            "service_charge": 0.05,
            "service_tax": 0.01,
            "settled_on": "2022-05-26T15: 06: 14+05: 30",
            "settled_orders_count": null,
            "settlement_amount": 10,
            "settlement_id": 6151,
            "settlement_initiated_on": "2022-05-26T15: 06: 09+05: 30",
            "settlement_type": "On-demand",
            "status": "FAILED",
            "utr": null,
            "vendor_id": 46695,
            "vendor_transaction_amount": 10
        },
        "event_time": "2022-05-26T15:06:15+05:30",
        "type": "VENDOR_SETTLEMENT_FAILED"
    }
}

Vendor Settlement Reversed

//Standard Settlement

{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 50,
            "payment_amount": null,
            "payment_from": "2022-04-01",
            "payment_till": "2022-04-01",
            "reason": null,
            "service_charge": 0.25,
            "service_tax": 0.05,
            "settled_on": "2022-04-01T15:03:31+05:30",
            "settled_orders_count": null,
            "settlement_amount": 50,
            "settlement_id": 3598,
            "settlement_initiated_on": "2022-04-01T13:51:00+05:30",
            "settlement_type": "STANDARD",
            "status": "REVERSED",
            "utr": 98756789343,
            "vendor_id": IS_1hour_Upi,
            "vendor_transaction_amount": 50
        },
        "event_time": "2022-04-01T16:47:12+05:30",
        "type": "VENDOR_SETTLEMENT_REVERSED"
    }
}
//Instant Settlement

{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 50,
            "payment_amount": null,
            "payment_from": "2022-04-01",
            "payment_till": "2022-04-01",
            "reason": null,
            "service_charge": 0.25,
            "service_tax": 0.05,
            "settled_on": "2022-04-01T15:03:31+05:30",
            "settled_orders_count": null,
            "settlement_amount": 50,
            "settlement_id": 3598,
            "settlement_initiated_on": "2022-04-01T13:51:00+05:30",
            "settlement_type": "INSTANT",
            "status": "REVERSED",
            "utr": 98756789343,
            "vendor_id": 46696,
            "vendor_transaction_amount": 50
        },
        "event_time": "2022-04-01T16:47:12+05:30",
        "type": "VENDOR_SETTLEMENT_REVERSED"
    }
}
//On-demand Settlement

{
    "data": {
        "settlement": {
            "adjustment": 0,
            "amount_settled": 50,
            "payment_amount": null,
            "payment_from": "2022-04-01",
            "payment_till": "2022-04-01",
            "reason": null,
            "service_charge": 0.25,
            "service_tax": 0.05,
            "settled_on": "2022-04-01T15:03:31+05:30",
            "settled_orders_count": null,
            "settlement_amount": 50,
            "settlement_id": 3598,
            "settlement_initiated_on": "2022-04-01T13:51:00+05:30",
            "settlement_type": "On-demand",
            "status": "REVERSED",
            "utr": 98756789343,
            "vendor_id": 46696,
            "vendor_transaction_amount": 50
        },
        "event_time": "2022-04-01T16:47:12+05:30",
        "type": "VENDOR_SETTLEMENT_REVERSED"
    }
}

Payload Field Description

FieldDescriptionExample
adjustmentSum of refunds, disputes, and chargeback part of this settlement is displayed here.0
amount_settledTotal amount that is settled in this schedule option.50
payment_amountTotal transaction amount considered for settlement.100
payment_fromStart date from which the payments are considered for settlement.2022-03-15
payment_tillEnd date till which the payments are considered for settlement.2022-03-23
reasonReason for failed and reversed settlements. Click here to know more.Transfer mode not valid for beneficiary.
service_chargeService charges applicable for the payments that are included in this settlement.2
service_taxService tax applicable for the payments that are included in this settlement.0.50
settled_onDate and time at which the settlement was processed.2022-03-17T14:21:18+05:30
settlement_amountSum of net settlement amount for the payments part of this settlement.13
settlement_idCashfree settlement ID1155353
settlement_initiated_onDate on which settlement was initiated.2022-03-17T14:29:21+05:30
settlement_typeIndicates if it is an instant settlement.INSTANT
statusStatus of the settlement (either INITIATED, SUCCESS, FAILED, or REVERSED)SUCCESS
utrUnique transaction reference number given by the bank for the settlement.N076221079016329
vendor_idReference ID as shared by the merchant while onboarding the vendor.IS_1hour_Upi
vendor_transaction_amountTransaction amount split of vendor50
event_timeTime at which settlement webhook was initiated.2022-03-17T14:29:23+05:30
typeType of webhook - VENDOR_SETTLEMENT_INITIATED,
VENDOR_SETTLEMENT_SUCCESS, VENDOR_SETTLEMENT_FAILED, or VENDOR_SETTLEMENT_REVERSED..
VENDOR_SETTLEMENT_SUCCESS

Possible Failure and Reversal Reasons

Reasons
Due to some technical issues at the bank, your amount will be settled in the next settlement cycle.
The IFSC you have provided for the bank account is invalid, write to [email protected] with the valid IFSC.
Bank account details you have provided are invalid, write to [email protected] with the updated account details.
Due to some technical error at the bank, your amount will be settled in the next settlement cycle.
Due to some technical issues, your amount will be settled in the next settlement cycle.
Settlements to NRE bank accounts is currently not possible, write to [email protected] with the updated account details.
Bank account details you have provided is not active, write to [email protected] with the updated account details.
You have exceeded the transfer limit for this settlement cylcle. We will process your settlement in the next settlement cycle.
Beneficiary name you have provided is incorrect, write to [email protected] with the updated details.
Unable to settle amount to this beneficiary account, write to [email protected] with the updated account details.
Your bank account details or the IFSC you have provided is invalid, write to [email protected] with the updated details.
Bank account details you have provided is invalid, write to [email protected] with the updated details.

Signature Verification

The signature must be used to verify if the request has not been tampered with. To verify the signature at your end, you will need your Cashfree PG secret key along with the payload.

timestamp is present in the header x-webhook-timestamp
Actual signature is present in the header x-webhook-signature

timestamp := 1617695238078;  
signedPayload := $timestamp.$payload;
expectedSignature := Base64Encode(HMACSHA256($signedPayload, $merchantSecretKey));

Compute Signature and Verify

Sample Code

Verify Signature using SDK

var express = require('express')
import { Cashfree } from "cashfree-pg"; 
var app = express()

Cashfree.XClientId = "<x-client-id>";
Cashfree.XClientSecret = "<x-client-secret>";
Cashfree.XEnvironment = Cashfree.Environment.SANDBOX;

app.post('/webhook', function (req, res) {
    try {
        Cashfree.PGVerifyWebhookSignature(req.headers["x-webhook-signature"], req.rawBody, req.headers["x-webhook-timestamp"]))
    } catch (err) {
        console.log(err.message)
    }
})
import (
  cashfree "github.com/cashfree/cashfree-pg/v4"
)

// Route
e.POST("/webhook", _this.Webhook)

// Controller
func (_this *WebhookRoute) Webhook(c echo.Context) error {
  	clientId := "<x-client-id>"
		clientSecret := "<x-client-secret>"
		cashfree.XClientId = &clientId
		cashfree.XClientSecret = &clientSecret
		cashfree.XEnvironment = cashfree.SANDBOX
  
    signature := c.Request().Header.Get("x-webhook-signature")
    timestamp := c.Request().Header.Get("x-webhook-timestamp")
    
    body, _ := ioutil.ReadAll(c.Request().Body)
    rawBody := string(body)
    webhookEvent, err := cashfree.PGVerifyWebhookSignature(signature, rawBody, timestamp)
    if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println(webhookEvent.Object)
	}
}
<?php

$inputJSON = file_get_contents('php://input');

$expectedSig = getallheaders()['x-webhook-signature'];
$ts = getallheaders()['x-webhook-timestamp'];

if(!isset($expectedSig) || !isset($ts)){
    echo "Bad Request";
    die();
}

\Cashfree\Cashfree::$XClientId = "<x-client-id>";
\Cashfree\Cashfree::$XClientSecret = "<x-client-secret>";
$cashfree = new \Cashfree\Cashfree();

try {
 $response =  cashfree->PGVerifyWebhookSignature($expectedSig, $inputJSON, $ts);
} catch(Exception $e) {
  // Error if signature verification fails
}
?>
from cashfree_pg.api_client import Cashfree

@app.route('/webhook', methods = ['POST'])
def disp():
		# Get the raw body from the request
    raw_body = request.data
  
    # Decode the raw body bytes into a string
    decoded_body = raw_body.decode('utf-8')

    #verify_signature
    timestamp = request.headers['x-webhook-timestamp']
    signature = request.headers['x-webhook-signature'
		
		cashfree = Cashfree()
		cashfree.XClientId = "<app_id>"
		cashfree.XClientSecret = "<secret_key>"
		try:
			cashfreeWebhookResponse = cashfree.PGVerifyWebhookSignature(signature, decoded_body, timestamp)
		except:
			# If Signature mis-match
import com.cashfree.*;

@PostMapping("/my-endpoint")
public String handlePost(HttpServletRequest request) throws IOException {      
    Cashfree.XClientId = "<x-client-id>";
		Cashfree.XClientSecret = "<x-client-secret>";
		Cashfree.XEnvironment = Cashfree.SANDBOX;
  
  	StringBuilder stringBuilder = new StringBuilder();
    BufferedReader bufferedReader = null;

    try {           
      bufferedReader = request.getReader();
      String line;
      while ((line = bufferedReader.readLine()) != null) {
              stringBuilder.append(line).append('\n');
      }
        
        
      String rawBody = stringBuilder.toString();
      String signature = request.getHeader("x-webhook-signature");
      String timestamp = request.getHeader("x-webhook-timestamp");
        
      Cashfree cashfree = new Cashfree();
      PGWebhookEvent webhook = cashfree.PGVerifyWebhookSignature(signature, rawBody, timestamp);
          
    } catch (Exception e) {
            // Error if verification fails
    } finally {
         if (bufferedReader != null) {
            bufferedReader.close();
		}
	}
      
}
using cashfree_pg.Client;
using cashfree_pg.Model;


		[Route("api/[controller]")]
    [ApiController]
    public class YourController : ControllerBase
    {
        [HttpPost]
        public async Task<IActionResult> Post()
        {
            // Read the raw body of the POST request
            using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
            {
                string requestBody = await reader.ReadToEndAsync();
                var headers = Request.Headers;
                var signature = headers["x-webhook-signature"];
                var timestamp = headers["x-webhook-timestamp"];
                
                Cashfree.XClientId = "<x-client-id>";
                Cashfree.XClientSecret = "<x-client-secret>";
                Cashfree.XEnvironment = Cashfree.SANDBOX;
								var cashfree = new Cashfree();
                
                try {
                var response = cashfree.PGVerifyWebhookSignature(signature, requestBody, timestamp);
                } catch(Exception e) {
                // Error if signature mis matches
                }
            }
        }
    }

Compute Signature and Verify manually

function verify(ts, rawBody){
    const body = req.headers["x-webhook-timestamp"] + req.rawBody;
    const secretKey = "<your secret key>";
    let genSignature = crypto.createHmac('sha256',secretKey).update(body).digest("base64");
    return genSignature
}
func VerifySignature(expectedSig string, ts string, body string) (string, error) {
	t := time.Now()
	currentTS := t.Unix()
	if currentTS-ts > 1000*300 {
		return "", errors.New("webhook delivered too late")
	}
	signStr := strconv.FormatInt(ts, 10) + body
	fmt.Println("signing String: ", signStr)
	key := ""
	h := hmac.New(sha256.New, []byte(key))
	h.Write([]byte(signStr))
	b := h.Sum(nil)
	return base64.StdEncoding.EncodeToString(b), nil
}

timestamp := c.Request().Header.Get("x-webhook-timestamp")
body, _ := ioutil.ReadAll(c.Request().Body)
rawBody := string(body)
signature := c.Request().Header.Get("x-webhook-signature")

VerifySignature(signature, timestamp, rawBody)
function computeSignature($ts, $rawBody){
    $rawBody = file_get_contents('php://input');
		$ts = getallheaders()['x-webhook-timestamp'];
  
    $signStr = $ts . $rawBody;
    $key = "";
    $computeSig = base64_encode(hash_hmac('sha256', $signStr, $key, true));
    return $computeSig;
}
public String generateSignature() {

	bufferedReader = request.getReader();
  String line;
  while ((line = bufferedReader.readLine()) != null) {
     stringBuilder.append(line).append('\n');
  }      
  String payload = stringBuilder.toString();
  String timestamp = request.getHeader("x-webhook-timestamp");
      
  String data = timestamp+payload;

  String secretKey = "SECRET-KEY"; // Get secret key from Cashfree Merchant Dashboard;
  Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
  SecretKeySpec secret_key_spec = new SecretKeySpec(secretKey.getBytes(),"HmacSHA256");
  sha256_HMAC.init(secret_key_spec);
  String computed_signature = Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(data.getBytes()));
  return computed_signature; // compare with "x-webhook-signature"
}
import base64
import hashlib
import hmac

def generateSignature():    
    # Get the raw body from the request
    raw_body = request.data
  
    # Decode the raw body bytes into a string
    payload = raw_body.decode('utf-8')

    #verify_signature
    timestamp = request.headers['x-webhook-timestamp']
    
    signatureData = timestamp+payload
    message = bytes(signatureData, 'utf-8')
    secretkey=bytes("Secret_Key",'utf-8') #Get Secret_Key from Cashfree Merchant Dashboard.
    signature = base64.b64encode(hmac.new(secretkey, message, digestmod=hashlib.sha256).digest())
    computed_signature = str(signature, encoding='utf8')
    return computed_signature #compare with "x-webhook-signature"


Subscribe to Developer Updates