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

# Dispute Webhooks

> Learn in detail about dispute webhooks.

Dispute webhooks can be configured to receive automated notifications when disputes are created, updated and closed.

The webhook notification will be sent on all the URLs added and enabled under the dispute webhook. Merchants can add new URLs and enable or disable existing URLs for refund webhook at any point in time and it will be reflected instantaneously.

| Webhook          | Description                                                                                                                                                                                                                                              |
| :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| DISPUTE\_CREATED | Dispute\_created webhook will be triggered when a new dispute is created.                                                                                                                                                                                |
| DISPUTE\_UPDATED | Dispute\_updated webhook will be triggered when a dispute is updated, for example when a comment is added by the Cashfree team, when the dispute moves into further stages like Pre-arbitration, Arbitration, or when the status of the dispute changes. |
| DISPUTE\_CLOSED  | This webhook will be triggered when a dispute is closed.                                                                                                                                                                                                 |

Click [here](/payments/online/webhooks/overview) to know how to configure webhooks.

## Dispute created

**Sample Payload**

```json theme={"dark"}
"{
  "data": {
    "dispute": {
      "dispute_id": "433475258",
      "dispute_type": "DISPUTE",
      "reason_code": "1402",
      "reason_description": "Duplicate Processing",
      "dispute_amount": 3,
      "created_at": "2023-06-15T21:49:48+05:30",
      "updated_at": "2023-06-15T21:49:48+05:30",
      "respond_by": "2023-06-18T23:59:59+05:30",
      "dispute_status": ""DISPUTE_CREATED"",
      "cf_dispute_remarks": "Dispute is created, please take action",
      "dispute_action_on": "MERCHANT"
    },
    "order_details": {
      "order_id": "order_1944392DR1kMTFYdIf8bI2awAcC3i9FTa",
      "order_amount": 3,
      "order_currency": "INR",
      "cf_payment_id": 885473311,
      "payment_amount": 3,
      "payment_currency": "INR"
    },
    "customer_details": {
      "customer_name": "Dileep Kumar s",
      "customer_phone": "8000000000",
      "customer_email": "dileep@gmail.com"
    }
  },
  "event_time": ""2023-06-15T21:50:04+05:30",
  "type": "DISPUTE_CREATED"
}"
```

## Dispute updated

**Sample Payload**

```json theme={"dark"}
"{
  "data": {
    "dispute": {
      "dispute_id": "433475257",
      "dispute_type": "PRE_ARBITRATION",
      "reason_code": "13.1",
      "reason_description": "Merchandise / Services Not Received",
      "dispute_amount": 40000,
      "created_at": "2023-06-15T21:16:03+05:30",
      "updated_at": "2023-06-15T21:19:15+05:30",
      "respond_by": "2023-06-19T23:59:59+05:30",
      "dispute_status": "PRE_ARBITRATION_CREATED",
      "cf_dispute_remarks": "Pre Arbitration request has been raised for this case.\nTarget Date :: 2023-06-18T00:00 -> 2023-06-19T23:59:59.",
      "dispute_update": "TYPE_UPDATE",
      "dispute_action_on": "MERCHANT"
    },
    "order_details": {
      "order_id": "order_1944392D4jHtCeVPPdTXkaUwg5cfnujQe",
      "order_amount": 40000,
      "order_currency": "INR",
      "cf_payment_id": 885457437,
      "payment_amount": 40000,
      "payment_currency": "INR"
    },
    "customer_details": {
      "customer_name": "Dileep Kumar s",
      "customer_phone": "8000000000",
      "customer_email": "dileep@gmail.com"
    }
  },
  "event_time": "2023-06-15T21:20:24+05:30",
  "type": "DISPUTE_UPDATED"
}"
```

## Dispute closed

**Sample Payload**

```json theme={"dark"}
"{
  "data": {
    "dispute": {
      "dispute_id": "433475257",
      "dispute_type": "CHARGEBACK",
      "reason_code": "4855",
      "reason_description": "Goods or Services Not Provided",
      "dispute_amount": 4500,
      "created_at": "2023-06-15T21:16:03+05:30",
      "updated_at": "2023-06-15T21:16:51+05:30",
      "respond_by": "2023-06-18T00:00:00+05:30",
      "resolved_at": "2023-06-15T21:16:51.682836678+05:30",
      "dispute_status": "CHARGEBACK_MERCHANT_WON",
      "cf_dispute_remarks": "Chargeback won by merchant"
    },
    "order_details": {
      "order_id": "order_1944392D4jHtCeVPPdTXkaUwg5cfnujQe",
      "order_amount": 4500,
      "order_currency": "INR",
      "cf_payment_id": 885457437,
      "payment_amount": 4500,
      "payment_currency": "INR"
    },
    "customer_details": {
      "customer_name": "Dileep Kumar s",
      "customer_phone": "8000000000",
      "customer_email": "dileep@gmail.com"
    }
  },
  "event_time": "2023-06-15T21:17:14+05:30",
  "type": "DISPUTE_CLOSED"
}"
```

## Payload field description

| Field                | Description                                                                                                                              | Example                             | Type          |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------------- |
| dispute\_id          | Cashfree’s unique ID to identify a dispute.                                                                                              | 433475257                           | Long          |
| dispute\_type        | Type of dispute created. Possible values:  <br />- DISPUTE<br />- RETRIEVAL<br />- CHARGEBACK<br />- PRE\_ARBITRATION<br />- ARBITRATION | Chargeback                          | String        |
| reason\_code         | Condition for which the customer is filing the case. See [dispute reason codes](/payments/manage/disputes/reason-codes) to know more.    | 13.6                                | String        |
| reason\_description  | Description of the reason code. Codes for Chargeback cases are specified by Card networks/NPCI.                                          | Credit not processed                | String        |
| dispute\_amount      | The amount for which the dispute has been created.                                                                                       | 4500                                | BigDecimal    |
| created\_at          | Time on which the dispute was registered on Cashfree’s system.                                                                           | 2023-06-15T21:16:03+05:30           | LocalDateTime |
| updated\_at          | Time on which the dispute was updated.                                                                                                   | 2023-06-15T21:16:51+05:30           | LocalDateTime |
| respond\_by          | Time by which the merchant is expected to respond to the dispute.                                                                        | 2023-06-18T00:00:00+05:30           | LocalDateTime |
| dispute\_status      | Status of Dispute. All possible values are listed in the table below.                                                                    | CHARGEBACK\_CREATED                 | String        |
| cf\_dispute\_remarks | Any remarks specified by Cashfree on the dispute.                                                                                        | Please submit documents.            | String        |
| dispute\_update      | Specifies what has been updated on the dispute. Possible Values:  <br />- STATUS\_UPDATE<br />- TYPE\_UPDATE<br />- COMMENT\_UPDATE      | TYPE\_UPDATE                        | String        |
| dispute\_action\_on  | Specifies whether the action is on Cashfree or Merchant at a time. Possible Values:  <br />- MERCHANT<br />- CASHFREE                    | MERCHANT                            | String        |
| resolved\_at         | Time on which the dispute was resolved/closed.                                                                                           | 2023-06-15T21:16:51.682836678+05:30 | LocalDateTime |
| event\_time          | Time at which dispute webhook was initiated.                                                                                             | 2023-06-15T21:16:51+05:30           | LocalDateTime |
| type                 | Type of webhook. Possible Values:  <br />- DISPUTE\_CREATED<br />- DISPUTE\_UPDATED<br />- DISPUTE\_CLOSED                               | DISPUTE\_CREATED                    | String        |

| List of dispute status                   |
| :--------------------------------------- |
| DISPUTE\_CREATED                         |
| DISPUTE\_DOCS\_RECEIVED                  |
| DISPUTE\_UNDER\_REVIEW                   |
| DISPUTE\_MERCHANT\_WON                   |
| DISPUTE\_MERCHANT\_LOST                  |
| DISPUTE\_MERCHANT\_ACCEPTED              |
| DISPUTE\_INSUFFICIENT\_EVIDENCE          |
| RETRIEVAL\_CREATED                       |
| RETRIEVAL\_DOCS\_RECEIVED                |
| RETRIEVAL\_UNDER\_REVIEW                 |
| RETRIEVAL\_MERCHANT\_WON                 |
| RETRIEVAL\_MERCHANT\_LOST                |
| RETRIEVAL\_MERCHANT\_ACCEPTED            |
| RETRIEVAL\_INSUFFICIENT\_EVIDENCE        |
| CHARGEBACK\_CREATED                      |
| CHARGEBACK\_DOCS\_RECEIVED               |
| CHARGEBACK\_UNDER\_REVIEW                |
| CHARGEBACK\_MERCHANT\_WON                |
| CHARGEBACK\_MERCHANT\_LOST               |
| CHARGEBACK\_MERCHANT\_ACCEPTED           |
| CHARGEBACK\_INSUFFICIENT\_EVIDENCE       |
| PRE\_ARBITRATION\_CREATED                |
| PRE\_ARBITRATION\_DOCS\_RECEIVED         |
| PRE\_ARBITRATION\_UNDER\_REVIEW          |
| PRE\_ARBITRATION\_MERCHANT\_WON          |
| PRE\_ARBITRATION\_MERCHANT\_LOST         |
| PRE\_ARBITRATION\_MERCHANT\_ACCEPTED     |
| PRE\_ARBITRATION\_INSUFFICIENT\_EVIDENCE |
| ARBITRATION\_CREATED                     |
| ARBITRATION\_DOCS\_RECEIVED              |
| ARBITRATION\_UNDER\_REVIEW               |
| ARBITRATION\_MERCHANT\_WON               |
| ARBITRATION\_MERCHANT\_LOST              |
| ARBITRATION\_MERCHANT\_ACCEPTED          |
| ARBITRATION\_INSUFFICIENT\_EVIDENCE      |

## Compute Signature and Verify

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

````bash theme={"dark"}
timestamp := 1617695238078;  
signedPayload := $timestamp.$payload;
expectedSignature := Base64Encode(HMACSHA256($signedPayload, $merchantSecretKey));```
````

## Sample code

### Verify Signature using SDK

<CodeGroup>
  ```node Node (express) theme={"dark"}

  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)
      }
  })
  ```

  ```go Go theme={"dark"}
  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)
      }
  })
  ```

  ```php PHP theme={"dark"}

  <?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
  }
  ?>

  ```

  ```python Python theme={"dark"}
  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

  ```

  ```java Java theme={"dark"}
  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();
  		}
  	}
        
  }
  ```

  ```c C# theme={"dark"}
  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
                  }
              }
          }
      }
  ```
</CodeGroup>

### Compute Signature and Verify manually

<CodeGroup>
  ```node Node (express) theme={"dark"}

  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
  }
  ```

  ```go Go theme={"dark"}
  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)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)
  ```

  ```php PHP theme={"dark"}

  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;
  }

  ```

  ```java Java theme={"dark"}
  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"
  }

  ```

  ```python Python theme={"dark"}
  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"

  ```
</CodeGroup>
