# Refund

> Discover Antom's refund rules and learn how to initiate a refund for a successful transaction.

Discover Antom's refund rules and learn how to initiate a refund for a successful transaction.

# Refund rules

The following are the relevant refund rules:

-   **Commission fee**: Whether the commission fee is returned or whether there are additional charges for the refund is subject to the contract.
-   **Refund settlement rate**: When the settlement and payment currency are inconsistent, the settlement exchange rate used for refund is the Antom exchange rate on the day of the successful refund.
-   **Refund restriction**: Different payment methods have different restrictions. The following are specific situations:

-   Refund not supported
-   Partial refund not supported
-   Refunds are not supported after a certain time, starting from the time of successful payment.

For details, see [payment methods](https://docs.antom.com/payment_methods.md).

-   **Refund return**: In extreme cases, due to the abnormal status of the buyer's bank account and other reasons, the **[refund](https://docs.antom.com/ac/ams/refund_online.md)** API is called and returns a successful refund status, but the buyer is unable to receive the funds successfully. Antom will settle the corresponding funds and notify you through the financial report settlement. You need to decide how to handle the funds.

# Refund methods

After the transaction is paid successfully, you can initiate a refund through the following two ways:

-   [Refund using the refund API](#x62q5): You can initiate a refund for a successfully paid transaction by calling the [**refund**](https://docs.antom.com/ac/ams/refund_online.md) API.
-   Refund in [Antom Dashboard](https://dashboard.alipay.com/global-payments/home): For more information about how to issue a refund and view the refund result, see [Refund transactions](https://docs.antom.com/ac/merchant_service/transactions.md#QySzf).

## Workflow

The following figure is the workflow of refund.

![Refund workflow diagram showing the end-to-end process for initiating a refund through the Antom API after a successful payment](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/c0cfacbe-3d0d-4319-a076-90c026692aaf.png)

1.  **Call the** [**refund**](https://docs.antom.com/ac/ams/refund_online.md) **API.**
2.  **Process the refund response.**Handle the result based on the response returned by the [**refund**](https://docs.antom.com/ac/ams/refund_online.md) API.
3.  **Obtain the refund result.**Obtain the refund result by using one of the following two methods:

-   Asynchronous notification: Specify _refundNotifyUrl_  in the [**refund**](https://docs.antom.com/ac/ams/refund_online.md) API to set the address for receiving asynchronous notifications, or configure a webhook URL in Antom Dashboard. When the payment is successful or failed, Antom will use [**notifyRefund**](https://docs.antom.com/ac/ams/notify_refund.md) to send asynchronous notifications to you.
-   Synchronous inquiry: Call the [**inquiryRefund**](https://docs.antom.com/ac/ams/ir_online.md) API to check the final refund result.

## Integration steps

Start your integration by taking the following steps:

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

### Step 1: Initiate a refund request Server-side

You can initiate a refund for a successfully paid transaction by calling the [**refund**](https://docs.antom.com/ac/ams/refund_online.md) API. The following sample code shows how to call the [**refund**](https://docs.antom.com/ac/ams_zh-cn/refund_online.md) API:

```java
public static void refund() {
    AlipayRefundRequest alipayRefundRequest = new AlipayRefundRequest();
    // replace with your refundRequestId
    String refundRequestId = UUID.randomUUID().toString();
    alipayRefundRequest.setRefundRequestId(refundRequestId);
    alipayRefundRequest.setPaymentId("20181129190741010007000000XXXX");
    alipayRefundRequest.setRefundReason("demo refund");

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

If the refund request does not meet relevant requirements when using the API, Antom will return corresponding error codes:

| **Error code** | **Description** |
| --- | --- |
| ORDER\_STATUS\_INVALID | The payment is not successful. |
| REFUND\_WINDOW\_EXCEED | The refund date exceeds the refundable period that is agreed in the contract. |
| PAYMENT\_METHOD\_NOT\_SUPPORTED | The payment method does not support canceling or refunding transactions. |
| PARTIAL\_REFUND\_NOT\_SUPPORTED | A partial refund is not supported for this transaction. |
| MERCHANT\_BALANCE\_NOT\_ENOUGH | The merchant balance is insufficient. |

The key parameters for initiating a [**refund**](https://docs.antom.com/ac/ams/refund_online.md) request are as follows:

| **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| _refundRequestId_ | Yes | The unique identifier that you assign to a refund. |
| _paymentId_ | Yes | The payment transaction ID assigned by Antom corresponding to this refund. The value of this parameter must match the _paymentId_ in the [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md) notification. |
| _refundAmount_ | Yes | The refund amount. It includes the following parameters: - _currency_: The refund currency. This value must match the _paymentAmount.currency_ in the [**pay (One-time Payments)**](https://docs.antom.com/ac/ams/payment_cashier.md) or [**createPaymentSession (One-time Payments)**](https://docs.antom.com/ac/ams/session_cashier.md) API. - _value_: The refund amount (as a positive integer in the smallest currency unit). The single refund amount must be less than or equal to the payment amount (_paymentAmount.value_) in the [**pay (One-time Payments)**](https://docs.antom.com/ac/ams/payment_cashier.md) or [**createPaymentSession (One-time Payments)**](https://docs.antom.com/ac/ams/session_cashier.md) API, and the cumulative amount of multiple partial refunds must be less than or equal to the total amount for this _paymentId_ in the [**pay (One-time Payments)**](https://docs.antom.com/ac/ams/payment_cashier.md) or [**createPaymentSession (One-time Payments)**](https://docs.antom.com/ac/ams/session_cashier.md) API. |
| _refundNotifyUrl_ | No | The address for receiving asynchronous refund notifications from Antom. |

The following code shows a sample of initiating a [**refund**](https://docs.antom.com/ac/ams/refund_online.md) request:

```json
{
    "paymentId": "20181129190741010007000000XXXX",
    "refundReason": "amsdemorefund",
    "refundRequestId": "20181129190741020007000000XXXX",
    "refundAmount": {
        "currency": "USD",
        "value": "1000"
    }
}
```

The following shows the sample code of a response:

```json
{
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S",
    "resultMessage": "Success"
  },
  "refundAmount": {
    "value": "1000",
    "currency": "USD"
  },
  "refundTime": "2020-10-10T12:01:01+08:30",
  "paymentId": "20181129190741010007000000XXXX",
  "refundRequestId": "20181129190741020007000000XXXX",
  "refundId": "40181129190741020007000000XXXX"
}
```

The value of _result.resultStatus_ in the response represents the refund status of the transaction. Please handle the result according to the guidance provided:

| _**result.resultStatus**_ | **Message** | **Further action** |
| --- | --- | --- |
| `S` | Refund is successful. | No further action is needed. |
| `U` | Refund is being processed. | The following scenarios may occur: - `REFUND_IN_PROCESS`: Indicates that the refund is being processed. You can call the [**inquiryRefund**](https://docs.antom.com/ac/ams/ir_online.md) API to obtain the refund result or wait for the refund result notification. - Other error codes: Retry with the original request. > **Note**: In card payment scenarios, the [**refund**](https://docs.antom.com/ac/ams/refund_online.md) response will not return the successful refund status `S` synchronously. |
| `F` | Refund failed. | Please retry with a new _refundRequestId_. If the issue persists, contact Antom Technical Support. |

### Step 2: Receive the refund result Server-side

Antom will send the corresponding refund result to you via server interaction. You can obtain the refund result using one of the following methods:

-   Receive asynchronous notifications from Antom
-   Inquire about the refund result

#### Receive asynchronous notifications

Complete the following steps to receive notifications from the Antom [**notifyRefund**](https://docs.antom.com/ac/ams/notify_refund.md) API:

**1\. Configure the webhook URL to receive notifications**

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

-   Recommended If each of your orders 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**](https://docs.antom.com/ac/ams/refund_online.md) API.
-   If all your orders share a unified notification URL, you can set the webhook URL on [Antom Dashboard](https://dashboard.alipay.com/global-payments/developers/iNotify) through **Developer > Notification URL**. For detailed steps, refer to [Notification URL](https://docs.antom.com/ac/merchant_service/notification.md).

The following is the notification request sample code:

```json
{
    "notifyType": "REFUND_RESULT",
    "refundAmount": {
        "currency": "USD",
        "value": "100"
    },
    "refundId": "40181129190741020007000000XXXX",
    "refundRequestId": "20181129190741020007000000XXXX",
    "refundStatus": "SUCCESS",
    "refundTime": "2020-10-10T12:01:01+08:30",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}
```

The table below shows the possible values of _result.resultStatus_ in the request message. Please handle the result according to the guidance provided:

| _**result.resultStatus**_ | **Message** | **Further action** |
| --- | --- | --- |
| `S` | Refund is successful. | No further action is required. |
| `F` | Refund failed. | Please retry with a new _refundRequestId_. If the issue persists, contact Antom Technical Support. |

> **Note**: After initiating a refund, Antom sends asynchronous notifications to you by default. However, in some failure scenarios such as parameter anomalies, the [**refund**](https://docs.antom.com/ac/ams/refund_online.md) API will return `F`. In such cases, Antom will not send asynchronous notifications and it can be considered as a refund failure.

**2\. Verify the asynchronous notification**

If you receive an asynchronous notification from Antom, you are required to return the response in the [Sample code](https://docs.antom.com/ac/cashierpay/notifications.md#vQK5A) format, but you do not need to countersign the response.

You need to verify the signature of the refund notification sent by Antom.

```java
/**
 * 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();
}
```

Whether the refund is successful or not, each notification request must be responded to in the format specified below:

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

#### Inquire about the refund result

In addition to obtaining the refund result through the asynchronous notification, you can also inquire about the refund status by calling the [**inquiryRefund**](https://docs.antom.com/ac/ams/ir_online.md) API using the _refundRequestId_ from the refund request.

The following code shows how to call the [**inquiryRefund**](https://docs.antom.com/ac/ams/ir_online.md) API: 

```java
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:

```json
{
    "refundAmount": {
        "currency": "USD",
        "value": "1000"
    },
    "refundId": "40181129190741020007000000XXXX",
    "refundRequestId": "20181129190741020007000000XXXX",
    "refundStatus": "SUCCESS",
    "refundTime": "2024-12-10T22:02:02-08:00",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}
```

The table below shows the possible values of _refundStatus_ returned in the response, please handle the result according to the guidance provided:

| _**refundStatus**_ | **Message** | **Further action** |
| --- | --- | --- |
| `SUCCESS` | Refund is successful. | No further action is needed. |
| `FAIL` | Refund failed. | Please retry with a new _refundRequestId_. If the issue persists, contact Antom Technical Support. |
| `PROCESSING` | Refund is being processed. | Please continue to inquire about the refund status until a final result is obtained or a refund asynchronous notification is received. |

> **Common questions**
>
> **Q: Will the refund result be returned immediately after initiating a refund?**
>
> A: Not all payment methods can return the final refund status synchronously. Refer to the asynchronous notification result from [**notifyRefund**](https://docs.antom.com/ac/ams/notify_refund.md) for a final outcome.
>
> **Q: How long does it take for the buyer to receive the refund after it is successful?**
>
> A: A successful refund indicates that the payment method has accepted the buyer’s refund request. The specific time for funds to arrive depends on the payment method.
>
> **Q: Can I initiate refunds for card payment orders before initiating capture?**
>
> A: No, a refund request can only be initiated after the order has been captured.
>
> **Q: Why is the** **_paymentId_** **in the synchronous response of the** [**refund**](https://docs.antom.com/ac/ams/refund_online.md) **API inconsistent with the** **_paymentId_** **synchronously returned by the** [**pay (One-time Payments)**](https://docs.antom.com/ac/ams/payment_cashier.md) **or** [**createPaymentSession (One-time Payments)**](https://docs.antom.com/ac/ams/session_cashier.md) **API?**
>
> A: For [API-hosted card payment integration](https://docs.antom.com/ac/cashierpay/cardcollant.md), [Checkout Page integration](https://docs.antom.com/ac/cashierpay/HOSTEDCKP.md), and [Payment Element integration](https://docs.antom.com/ac/cashierpay/element.md), Antom allows buyers to return to the card information entry page for retry in certain payment failure scenarios. Each retry submission generates a new _paymentId_. Therefore, the _paymentId_ in the synchronous response of the [**refund**](https://docs.antom.com/ac/ams/refund_online.md) API may differ from the original _paymentId_ returned in the response of the [**pay (One-time Payments)**](https://docs.antom.com/ac/ams/payment_cashier.md) or [**createPaymentSession (One-time Payments)**](https://docs.antom.com/ac/ams/session_cashier.md)  API.