Refund

For successfully paid transactions, if a refund needs to be issued to the buyer, use one of the following methods:

  • Initiate the refund by calling the refund API.
  • Manually process the refund through the APO Dashboard.

For specific refund policies, such as processing fees, refund settlement exchange rates, and refund validity period, refer to the actual agreements set by related acquirers.

Notes:

For the Antom:

  • Detailed information about payment methods can be found in Supported payment methods.
  • Refund reversal: In rare cases, due to issues such as the buyer's abnormal account status on the bank's side, it may occur that after calling the refund API, the refund is marked as successful, but the buyer does not receive the funds. In such situations, Antom will settle the corresponding funds and notify you via the settlement bill. It is your responsibility to decide how to handle such funds.

Refund through APO Dashboard

You can issue a refund and check the refund details through APO Dashboard.

Refund using the refund API

The overall flow of the refund process is as follows:

退款英文.png

Figure 1. Workflow of refund

Integration steps

Start your integration by taking the following steps:

  1. Initiate a refund request
  2. Retrieve the refund result

Step 1: Initiate a refund request

The following requirements for a refund request must be met when you use the refund API. Otherwise, the corresponding error codes are to be returned by APO:

Refund detailsRequirements

Error code

Refund currency

The value of refundAmount.currency in the refund request must be consistent with the value of paymentAmount.currency used when initiating a payment.

CURRENCY_NOT_SUPPORT

Refund amount

The value of refundAmount.value in the refund request must not be less than the minimum refund amount (which is usually the same as the minimum payment amount) and no greater than the refundable amount of a payment.

REFUND_AMOUNT_EXCEED

Payment status

For card payments:

  • Only captured payments can be refunded.
  • For a payment where a chargeback occurs and the liability is not judged, a refund is not allowed.

ORDER_STATUS_INVALID

Refund period

The refund is allowed only when the refund is issued within the refund period of the corresponding payment method.

REFUND_WINDOW_EXCEED

Table 1. Refund requirements

The following sample code shows how to call the refund API:

copy
public static void refund() {
    AlipayRefundRequest alipayRefundRequest = new AlipayRefundRequest();
    // replace with your refundRequestId
    String refundRequestId = UUID.randomUUID().toString();
    alipayRefundRequest.setRefundRequestId(refundRequestId);
    alipayRefundRequest.setPaymentId("202505151940108001001889A0235440943");
    alipayRefundRequest.setRefundReason("demo refund");
alipayRefundRequest.setRefundNotifyUrl("https://kademo.intlalipay.cn/payments/notifySuccess");
    // set refund amount
    Amount amount = Amount.builder().currency("USD").value("1000").build();
    alipayRefundRequest.setRefundAmount(amount);

    AlipayRefundResponse alipayRefundResponse;
    try {
        alipayRefundResponse = CLIENT.execute(alipayRefundRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
        // handle error condition
    }
}

When initiating a refund through the refund API, the key parameters in the request are listed as follows:

Parameter

Is required?

 Description

refundRequestId

Yes

The unique identifier that you assign to a refund.

paymentId

Yes

The unique identifier that APO assigns to the original payment to be refunded.

refundAmount.value

Yes

The refund amount must be no less than the minimum refund amount (usually the same as the minimum payment amount) and no greater than the refundable amount of a payment.

refundAmount.currency

Yes

The currency of the refund. The currency of the refund amount must be consistent with the currency of the payment amount (paymentAmount.currency) in the pay API.

refundNotifyUrl

No

The URL for receiving asynchronous refund notifications. If you want to receive asynchronous notifications for refund results, please specify this field. If both the request and the APO Dashboard have specified refund notification URLs, the value specified in the request takes precedence.

Table 2. Key parameters of refund requests

The following shows the sample code of a refund request: 

copy
{
    "paymentId": "20241212194010800100188670211082739",
    "refundReason": "amsdemorefund",
    "refundRequestId": "yuqian_refund_654ac17e-bc5e-4648-b9de-a18f0a74aa2a",
    "refundAmount": {
        "currency": "SGD",
        "value": "1000"
    },
  "refundNotifyUrl":"https://kademo.intlalipay.cn/payments/notifySuccess"
}

The following shows the sample code of a response:

copy
{
    "acquirerInfo": {
        "acquirerMerchantId": "764764000015445",
        "acquirerName": "2C2P",
        "acquirerTransactionId": "750130125",
        "referenceRequestId": "2025043019031303099320289169177"
    },
    "acquirerReferenceNo": "2025043019031300010320289179466",
    "paymentId": "20250430194010890100111320263308754",
    "refundAmount": {
        "currency": "USD",
        "value": "110"
    },
    "refundId": "20250430194010890100111320263188180",
    "refundRequestId": "REFUND_20250430152656859_AUTO",
    "refundTime": "2025-04-30T00:26:58-07:00",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}

The table shows the possible values that the result.resultStatus field in the response message may return. Please handle the result according to the guidances:

result.resultStatus

Message

Further actions

S

Indicates that the refund is successful.

No further action is required. 

F

Indicates that the refund failed.

Please replace the refundRequestId and try again, or contact APO technical support.

U

Indicates that the refund is being processed.

The following scenarios may occur:

  • REFUND_IN_PROCESS: Indicates that the refund is being processed. You can call the inquiryRefund API to obtain the refund result or wait for the refund result notification.
  • UNKNOWN_EXCEPTIONREQUEST_TRAFFIC_EXCEED_LIMIT: Usually caused by APO system or network issues, you can call the refund API again using the original refundRequestId.

Step 2: Receive the refund result

After initiating a refund request, you can obtain the payment result using one of the following methods:

  • Receive asynchronous notifications
  • Inquire about the payment result

Set up asynchronous notifications

1. Set the webhook URL to receive notifications

You can choose one of following two methods to set the webhook URL to receive notifications:

  • RecommendedIf each of your order has a unique notification URL, we recommend to set the webhook URL in each individual request. You can pass the asynchronous notification receiving URL for the specific order through the refundNotifyUrl field in the refund API.
  • If all your orders share a unified notification URL, you can set the webhook URL on APO Dashboard through Developer > Notification Address.

Note: If both the request and the APO Dashboard have refund notification URLs specified, the value specified in the request takes precedence.

The following is the notification request sample code:

copy
{
    "notifyType": "REFUND_RESULT",
    "paymentId": "20250430194010890100111320263308754",
    "paymentRequestId": "PAYMENT_20250430151543077_AUTO",
    "refundAmount": {
        "currency": "USD",
        "value": "110"
    },
    "refundId": "20250430194010890100111320263188180",
    "refundRequestId": "REFUND_20250430152656859_AUTO",
    "refundStatus": "SUCCESS",
    "refundTime": "2025-04-30T00:26:58-07:00",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}

The table shows the possible values that the result.resultStatus field in the request message may return. Please handle the result according to the guidances:

result.resultStatus

Message

Further actions

S

Indicates that the refund is successful.

No further action is required.

F

Indicates that the refund failed.

Please replace the refundRequestId and try again, or contact APO technical support.

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 refund notification sent by Antom.

copy
/**
 * receive notify
 *
 * @param request    request
 * @param notifyBody notify body
 * @return Result
 */
@PostMapping("/receiveNotify")
@ResponseBody
public Result receiveNotify(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");

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

        // deserialize the notification body
        JSONObject jsonObject = JSON.parseObject(notifyBody);
        String notifyType = (String)jsonObject.get("notifyType");
        if("REFUND_RESULT".equals(notifyType)){
            AlipayRefundNotify paymentNotify = jsonObject.toJavaObject(AlipayRefundNotify.class);
            if (paymentNotify != null && "SUCCESS".equals(paymentNotify.getResult().getResultCode())) {
                // handle your own business logic.
                // e.g. The relationship between payment information and users is kept in the database.
                System.out.println("receive payment notify: " + JSON.toJSONString(paymentNotify));
                return Result.builder().resultCode("SUCCESS").resultMessage("success.").resultStatus(ResultStatusType.S).build();
            }
        }
        // other types of notifications
        
    } catch (Exception e) {
        // handle error condition
        return Result.builder().resultCode("FAIL").resultMessage("fail.").resultStatus(ResultStatusType.F).build();
    }

    return Result.builder().resultCode("SYSTEM_ERROR").resultMessage("system error.").resultStatus(ResultStatusType.F).build();
}

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

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

Inquire refunds

In addition to obtaining the refund result through the asynchronous notification, you can retrieve the corresponding refund result through the inquire refunds service. You can call the inquiryRefund API and use the refundRequestId from the refund session to check the refund status. 

The following code shows how to call the inquiryRefund API: 

copy
public static void inquiryRefund() {
    AlipayInquiryRefundRequest alipayInquiryRefundRequest = new AlipayInquiryRefundRequest();

    // replace with your refundId
    alipayInquiryRefundRequest.setRefundId("yourRefundId");

    AlipayInquiryRefundResponse alipayInquiryRefundResponse = null;
    try {
        alipayInquiryRefundResponse = CLIENT.execute(alipayInquiryRefundRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
        // handle error condition
    }
}

The following code shows an example of a response:

copy
{
    "acquirerInfo": {
        "acquirerMerchantId": "764764000015445",
        "acquirerName": "2C2P",
        "acquirerTransactionId": "750130125",
        "referenceRequestId": "2025043019031303099320289169177"
    },
    "refundAmount": {
        "currency": "USD",
        "value": "110"
    },
    "refundId": "20250430194010890100111320263188180",
    "refundRequestId": "REFUND_20250430152656859_AUTO",
    "refundStatus": "SUCCESS",
    "refundTime": "2025-04-30T00:26:58-07:00",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}

The table shows the possible values of refundStatus returned in the response:

refundStatus

Message

Further actions

SUCCESS

Indicates that the refund is successful.

No further action is required.

FAIL

Indicates that the refund failed.

Please replace the refundRequestId and try again, or contact APO technical support.

PROCESSING

Indicates that the refund is processing.

Please continue to inquire about the refund status until a final result is obtained or a refund asynchronous notification is received.

Commom questions

Q: Will the refund result be returned immediately after initiating a refund?

A: Not all payment methods can provide an immediate final refund result, so please refer to the refund result from asynchronous notifications.

Q: How long does it take for the buyer to receive the refund after it is successful?

A: A successful refund means the issuing bank has processed the buyer's refund request. The exact time for the funds to be credited depends on the issuing bank.