Dispute

In the event of a dispute, APO provides a unified dispute notification. APO is only responsible for sending notifications. For detailed information on the specific dispute resolution process, contact the relevant acquirer. Typically, acquirers follow these steps:

  • Notification of chargeback (NoC).
  • Handling of the dispute.
  • Notification of the liability in the dispute.

Note: Currently, only Antom and PayPal are supported. Other acquirers will gradually be supported in the future.

Receive a dispute notification

When a buyer initiates a dispute, you can obtain the dispute information by receiving a Notification of Dispute (NoD) sent by APO through the notifyDispute notification.

Step 1: Set the webhook URL to receive notifications

You need to set a notification URL before receiving asynchronous notifications. You can set the webhook URL on APO Dashboard through Developer > Notification Address. For detailed steps, refer to Notification URL.

The key parameters contained in the notification are listed as follows (For details, see the notifyDispute API):

Parameter

Description

disputeAmount

The amount of the transaction which has a dispute.

disputeId

The unique ID that is assigned by APO to identify a dispute.

disputeNotificationType

The type of dispute notification. Valid values are:

  • DISPUTE_CREATED: indicates that a dispute occurs, and you need to intervene to handle it. Antom and PayPal will return.
  • DISPUTE_JUDGED: indicates that the dispute is judged. Antom and PayPal will return.

defenseDueTime

The due time after which you cannot defend a dispute.

disputeSource

The card scheme that is responsible for processing the dispute.

The parameter is returned when the value of disputeNotificationType is DISPUTE_CREATED or DISPUTE_JUDGED.

paymentId

The unique ID that is assigned by APO to identify a payment.

paymentRequestId

The unique ID that is assigned by a merchant to identify a payment request.

Table 2. Key parameters of the notifyDispute notification

The following is the notification request sample code:

copy
{
  "acquirerInfo": {
    "acquirerMerchantId": "WH4P43AMLR9W8",
    "acquirerName": "PAYPAL",
    "acquirerReasonCode": "DUPLICATE_TRANSACTION",
    "acquirerReasonDescription": "The transaction was a duplicate",
    "acquirerTransactionId": "PP-R-VAD-568996120"
  },
  "defendable": true,
  "disputeAmount": {
    "currency": "USD",
    "value": "999"
  },
  "disputeId": "2025033129013101081705064668",
  "disputeNotificationType": "DISPUTE_CREATED",
  "disputeReasonCode": "2206",
  "disputeReasonMsg": "Duplicate Processing/Paid by Other Means",
  "disputeSource": "PAYPAL",
  "disputeTime": "2025-03-30T20:26:00-07:00",
  "disputeType": "CHARGEBACK",
  "paymentId": "20250331194010890100111070257852045",
  "paymentRequestId": "G153202503311054525768"
}

Step 2: Verify asynchronous notifications

If you receive an asynchronous notification from APO, you are required to return the response in the Sample code format, but you do not need to countersign the response.

You need to verify the signature of the dispute notification sent by APO.

copy
import javax.servlet.http.HttpServletRequest;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.alipay.global.api.model.Result;
import com.alipay.global.api.model.ResultStatusType;
import com.alipay.global.api.response.AlipayResponse;
import com.alipay.global.api.tools.WebhookTool;

@RestController
public class PaymentNotifyHandleBySDK {

    /**
     * alipay public key, used to verify signature
     */
    private static final String SERVER_PUBLIC_KEY = "";
            
    /**
     * payment result notify processor
     * using <a href="https://spring.io">Spring Framework</a>
     *
     * @param request    HttpServletRequest
     * @param notifyBody notify body
     * @return
     */
    @PostMapping("/payNotify")
    public Object payNotifyHandler(HttpServletRequest request, @RequestBody String notifyBody) {

        // retrieve the required parameters from http request.
        String requestUri = request.getRequestURI();
        String requestMethod = request.getMethod();

        // retrieve the required parameters from request header.
        String requestTime = request.getHeader("request-time");
        String clientId = request.getHeader("client-id");
        String signature = request.getHeader("signature");

        Result result;
        AlipayResponse response = new AlipayResponse();

        try {
            // verify the signature of notification
            boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId, requestTime, signature, notifyBody, SERVER_PUBLIC_KEY);
            if (!verifyResult) {
                throw new RuntimeException("Invalid notify signature");
            }

            // deserialize the notification body
            
            // update the order status with notify result

            // respond the server that the notification is received
            result = new Result("SUCCESS", "success", ResultStatusType.S);

        } catch (Exception e) {
            String errorMsg = e.getMessage();
            // handle error condition
            result = new Result("ERROR", errorMsg, ResultStatusType.F);
        }
        response.setResult(result);
        return ResponseEntity.ok().body(response);
    }

}

You do not need to countersign the response of the result notification. However, you must respond to each notification request in the following fixed format, regardless of whether the payment is successful or not. 

copy
{
    "result": {
        "resultCode": "SUCCESS",
        "resultStatus": "S",
        "resultMessage": "success"
    }
}

Notes:

  • After you have processed the notifications received from APO, record them and correctly handle idempotency to prevent duplicate processing of the same request.
  • Record the key information about the dispute, such as disputeId, paymentId, and paymentRequestId. Handle the dispute within the time limit specified by defenseDueTime.

Handle dispute

When dealing with a dispute, you may encounter one of the following scenarios:

  • Dispute cancellation: If the buyer cancels the dispute, you receive a notification of the dispute cancellation from APO. (Note: Only applicable to Antom.)
  • Accept the dispute: If you agree with the chargeback and the specific reason given, you can accept the dispute and use the dashboard of each acquirer to proceed.
  • Challenge the dispute: If you want to defend against the dispute, use the dashboard of each acquirer to defend the dispute.
  • Overdue warningYou must complete dispute resolution before the deadlines specified by each acquirer. If not handled promptly, APO will determine whether to forward asynchronous notifications based on the notification rules of the acquirer. (Note: Only applicable to Antom.)

Receive notification of dispute liability

When the dispute liability is determined, you will receive a notification where the value of disputeNotificationType is DISPUTE_JUDGED, and the value of disputeJudgedResult indicates the party deemed liable.

  • ACCEPT_BY_CUSTOMER: Buyer's liability.
  • ACCEPT_BY_MERCHANT: Merchant's liability. You are liable for the dispute loss.

When you receive the notification of dispute liability, you must return a response as instructed in the notifyDispute API. Otherwise, APO will resend the notification until a correct response is received.