Dispute Webhook Integration Document
1. Overview#
To help merchants receive timely updates on dispute progress, OpenAPI provides dispute Webhook notification capability.
Merchants can create Webhooks and subscribe to dispute-related events to receive asynchronous notifications when a dispute is created and when a dispute is closed.This capability applies to transactions initiated through OpenAPI. Only OpenAPI transactions will trigger the corresponding dispute Webhook.
Create Webhook API reference: https://docs-v2.useepay.com/233908796e0
2. Supported Event Types#
The following event types are currently supported:2.1 dispute.created#
Indicates that a new dispute event has been created.
Typical scenarios include:2.2 dispute.closed#
Indicates that the current dispute event has been closed.
Typical scenarios include:Dispute won by the merchant / chargeback reversed
Dispute lost by the merchant
2.3 Important Notes#
The meaning of dispute.closed is:The current dispute has been completed
It does not mean the entire order is permanently closed
It does not mean no further disputes can occur for this order
An order may first receive a retrieval
A formal chargeback may occur later
Or multiple dispute-related events may occur for the same order at different stages
Therefore, when receiving notifications, merchants should use the dispute ID data.id as the unique identifier for each individual dispute, rather than assuming that there can only be one dispute for an order based solely on merchant_order_id or payment_intent_id.
3. Rules for Creating a Webhook#
When creating a Webhook, merchants need to be aware of the following restrictions:3.1 Supported Subscribed Events#
When creating a Webhook, the following events can be subscribed to:3.2 api_version Restriction#
When creating a Webhook, api_version only supports the following version:If another version is passed, a parameter validation error should be returned.3.3 Event Type Validation#
When creating a Webhook, the system validates the event types passed by the merchant.
If an event type is not within the supported range, a parameter validation error should be returned.
4. Notification Payload Structure#
Dispute Webhooks use a unified event structure:{
"id": "Event ID",
"name": "Event type",
"data": {
"id": "Dispute order ID",
"status": "Dispute status",
"retrieval": false,
"amount": 500.23,
"currency": "USD",
"reason": "Dispute reason",
"merchant_no": "500000000008901",
"app_id": "www.pay.com",
"create_at": "2026-04-14T04:22:25Z",
"payment_intent_id": "1012604141216938827",
"merchant_order_id": "19d82600-e9d1-4f43-934d-18090d6db098",
"payment_method_details": {
"type": "card",
"brand": "visa"
}
}
}
5. Field Descriptions#
5.1 Top-level Fields#
| Field | Type | Description |
|---|
id | string | Webhook event ID, uniquely identifies one notification |
name | string | Event type. Possible values are dispute.created or dispute.closed |
data | object | Dispute business data |
5.2 data Field Description#
| Field | Type | Description |
|---|
id | string | Dispute order ID, uniquely identifies the current dispute |
status | string | Current dispute status |
retrieval | boolean | Whether this is a retrieval. true indicates retrieval, false indicates a formal chargeback |
amount | number | Original disputed amount of this dispute |
amount_won | number | Amount actually won back in this dispute. Not returned if the merchant loses |
currency | string | Currency |
reason | string | Dispute reason |
reason_code | string | Dispute reason code |
merchant_no | string | Merchant number |
app_id | string | Application ID |
create_at | string | Dispute creation time, in UTC time and ISO 8601 format |
payment_intent_id | string | Corresponding payment order ID |
merchant_order_id | string | Merchant order ID |
payment_method_details | object | Payment method details |
5.3 payment_method_details Field Description#
| Field | Type | Description |
|---|
type | string | Payment method type, such as card, klarna |
brand | string | Card brand: visa, master, dc, jcb, ae |
6. Status Description#
The following status values are currently supported:| Status Value | Description |
|---|
need_response | The current dispute/retrieval still requires merchant action |
won | The merchant won or partially won. The specific won amount is determined by amount_won |
lost | The merchant lost |
warning_closed | The retrieval process has been closed |
retrieval = true indicates that the current event is a retrieval process.
retrieval = false indicates that the current event is a formal chargeback process.
dispute.closed only indicates that the current dispute has been closed. The final result is reflected by status.
When a formal chargeback is closed, status is won or lost.
When a retrieval is closed, status is warning_closed.
For partial-win scenarios, status remains won, and the specific won amount is determined by amount_won.
7. Event Lifecycle Description#
Merchants should pay special attention that disputes are processed at the dispute level, not as a one-time event at the order level.7.1 Typical Lifecycle of a Single Dispute#
A dispute generally goes through the following process:1.
A dispute event is generated
dispute.created is pushed
2.
The dispute enters the processing stage
The status may be need_response
3.
The dispute processing is completed
dispute.closed is pushed
7.2 The Same Order May Have Multiple Disputes#
The same merchant_order_id or payment_intent_id may correspond to multiple different disputes.
For example:Second dispute: formal chargeback
The first dispute has been closed
A new dispute is created later
Therefore, when designing their systems, merchants are advised to follow these principles:Use data.id as the primary key of the dispute
Use merchant_order_id / payment_intent_id as association dimensions
Do not assume that no further disputes will occur for the order after receiving one dispute.closed event
8. Dispute Notification Flow Diagram#
9. Payload Examples#
9.1 dispute.created Example#
{
"id": "evt_768654c9e6fe48c3a73e48108c5a9e0f",
"name": "dispute.created",
"data": {
"id": "2012604141222938830",
"status": "need_response",
"retrieval": false,
"amount": 100,
"currency": "USD",
"reason": "Goods/ services ordered but not received",
"reason_code": "unauthorized_purchase",
"merchant_no": "500000000008901",
"app_id": "www.pay.com",
"create_at": "2026-04-14T04:22:25Z",
"payment_intent_id": "1012604141216938827",
"merchant_order_id": "19d82600-e9d1-4f43-934d-18090d6db098",
"payment_method_details": {
"type": "card",
"brand": "visa"
}
}
}
9.2 dispute.closed Example#
9.2.1 Merchant Lost#
{
"id": "evt_45322c063a9f47bb89fc0204a406dc8b",
"name": "dispute.closed",
"data": {
"id": "2012604141356938847",
"status": "lost",
"retrieval": false,
"amount": 100,
"currency": "USD",
"reason": "Goods/ services ordered but not received",
"reason_code":"unauthorized_purchase",
"merchant_no": "500000000008901",
"app_id": "www.pay.com",
"create_at": "2026-04-14T05:56:11Z",
"payment_intent_id": "1012604141355938845",
"merchant_order_id": "889219a2-e50d-4cc5-b34f-0a5851b5be78",
"payment_method_details": {
"type": "klarna"
}
}
}
9.2.2 Merchant Fully Won#
{
"id": "evt_45322c063a9f47bb89fc0204a406dc8b",
"name": "dispute.closed",
"data": {
"id": "2012604141356938847",
"status": "won",
"retrieval": false,
"amount": 100,
"amount_won": 100,
"currency": "USD",
"reason": "Goods/ services ordered but not received",
"reason_code":"unauthorized_purchase",
"merchant_no": "500000000008901",
"app_id": "www.pay.com",
"create_at": "2026-04-14T05:56:11Z",
"payment_intent_id": "1012604141355938845",
"merchant_order_id": "889219a2-e50d-4cc5-b34f-0a5851b5be78",
"payment_method_details": {
"type": "klarna"
}
}
}
9.2.3 Merchant Partially Won#
{
"id": "evt_45322c063a9f47bb89fc0204a406dc8b",
"name": "dispute.closed",
"data": {
"id": "2012604141356938847",
"status": "won",
"retrieval": false,
"amount": 100,
"amount_won": 50,
"currency": "USD",
"reason": "Goods/ services ordered but not received",
"reason_code":"unauthorized_purchase",
"merchant_no": "500000000008901",
"app_id": "www.pay.com",
"create_at": "2026-04-14T05:56:11Z",
"payment_intent_id": "1012604141355938845",
"merchant_order_id": "889219a2-e50d-4cc5-b34f-0a5851b5be78",
"payment_method_details": {
"type": "klarna"
}
}
}
9.2.4 Retrieval Closed#
{
"id": "evt_45322c063a9f47bb89fc0204a406dc8b",
"name": "dispute.closed",
"data": {
"id": "2012604141356938847",
"status": "warning_closed",
"retrieval": true,
"amount": 100,
"currency": "USD",
"reason": "Goods/ services ordered but not received",
"reason_code":"unauthorized_purchase",
"merchant_no": "500000000008901",
"app_id": "www.pay.com",
"create_at": "2026-04-14T05:56:11Z",
"payment_intent_id": "1012604141355938845",
"merchant_order_id": "889219a2-e50d-4cc5-b34f-0a5851b5be78",
"payment_method_details": {
"type": "klarna"
}
}
}
10. Signature Verification#
After receiving the request, and after validating that all required parameters are complete, you should use the raw HTTP request body for signature verification.
Reference: https://docs-v2.useepay.com/7598891m011. Notes#
1.
Merchants must ensure that the Webhook URL is accessible and supports processing application/json request bodies.
2.
Merchants should design their data model based on the dispute dimension, rather than assuming that an order can only have one dispute.
3.
dispute.closed means the current dispute has been closed. It does not mean that no further disputes can occur for the order.
Modified at 2026-04-28 07:25:36