# Capture

> Learn how to capture authorized payments in APO through automatic or manual modes.

You can choose one of the two methods to capture funds:

-   Automatic capture
-   Manual capture

> **Note**:
>
> -   For card payments, it is recommended to confirm the capture is successful before shipping.
> -   For Antom, South Korean issuer-authenticated cards do not support manual capture; For 2C2P, South Korean cards issuer-authenticated do not need capture.
> -   For Antom, if you do not capture within 7 days after the buyer's authorized payment is successful, the transaction will be automatically cancelled. For other acquirers, please refer to their capture rules.

## Automatic capture

You must set the value of _paymentFactor.captureMode_ in the [**pay**](pay) API or [**createPaymentSession**](payment_session) API to `AUTOMATIC`. APO automatically captures funds after the buyer authorizes the payment. The capture result will be sent to you via an asynchronous notification.

## Manual capture

You must set the value of _paymentFactor.captureMode_ in the [**pay**](pay) API or [**createPaymentSession**](payment_session) API to `MANUAL`, and initiate fund capture by calling the [**capture**](capture_pay) API after successful authorization. The capture result will be sent to you via an asynchronous notification.

### Integration steps

Start your integration by taking the following steps:

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

#### Step 1: Initiate a capture request

The following sample code shows how to call the [**capture**](capture_pay) API:

```java
public static void capture() {
    AlipayCaptureRequest alipayCaptureRequest = new AlipayCaptureRequest();

    Amount amount = Amount.builder().currency("SGD").value("4200").build();
    alipayCaptureRequest.setCaptureAmount(amount);

    // replace with your captureRequestId
    String captureRequestId = UUID.randomUUID().toString();
    alipayCaptureRequest.setCaptureRequestId(captureRequestId);

    // replace with your paymentId
    alipayCaptureRequest.setPaymentId("20240101123456789XXXX");

    AlipayCaptureResponse alipayCaptureResponse = null;
    try {
        alipayCaptureResponse = CLIENT.execute(alipayCaptureRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
    }
}
```

When initiating a capture request through the [**capture**](capture_pay) API, the key parameters are listed as follows:

| **Parameter** | **Description** |
| --- | --- |
| _captureRequestId_ | A unique identifier that you assign to a capture request. |
| _paymentId_ | A unique identifier that APO assigns to an order. |
| _captureAmount.value_ | The capture amount, which must be less than or equal to the total authorized amount. |
| _captureAmount.currency_ | The currency of the capture amount. The currency must be consistent with the currency of the payment amount (_paymentAmount.currency_) in the [**pay**](https://idocsmng.alipay.com/spaces/ac/repos/apo/page/pay) API. |

Table 1. Key parameters in the [**capture**](capture_pay) API

The following shows the sample code of a capture request: 

```json
{
  "paymentId": "20220919194010890100111740275820195",
  "captureRequestId": "capture_cangxi_lj_20220920_005914_845",
  "captureAmount": {
    "currency": "HKD",
    "value": "10"
  }
}
```

The following shows the sample code of a capture response:

```json
{
  "acquirerInfo":{
    "acquirerMerchantId":"2181110021840423",
    "acquirerName":"ALIPAY",
    "acquirerResultCode":"SUCCESS",
    "acquirerResultMessage":"success",
    "acquirerTransactionId":"20250507114010807000181290271040256",
    "referenceRequestId":"20250507181369736538569428992"
  },
  "captureAmount":{
    "currency":"HKD",
    "value":"10"
  },
  "captureId":"20250507114010807000181290271040256",
  "captureRequestId":"20250507181369736538569428992",
  "captureTime":"2025-05-07T03:04:15-07:00",
  "paymentId":"20250507114010800100181290233266703",
  "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 capture is successful. | You can proceed with the order and save the APO side _captureId_ information for future refund handling. |
| `F` | Indicates that the capture failed. | Use a different _captureRequestId_ and try again, or contact APO technical support. |
| `U` | Indicates that the capture is being processed. | You can call the [**inquiryPayment**](https://docs.antom.com/ac/apo/paymentri_online.md) API to obtain the capture result or wait for the capture result notification. |

Table 2. Values of _resultStatus_ in the response

> **Note**: If you did not receive a response message, it might be due to a network timeout. You can call the [**inquiryPayment**](https://docs.antom.com/ac/apo/paymentri_online.md) API to obtain the capture result or wait for the capture result notification.

#### Step 2: Receive a capture response

After the buyer completes payment or the payment times out, APO will send the corresponding capture result to you via server interaction. Use one of the following methods to retrieve the capture result:

-   Receive an asynchronous notification
-   Inquire about the capture 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:

-   If you have set the asynchronous notification URL for the order in the _paymentNotifyUrl_ parameter when calling the **[pay](https://docs.antom.com/ac/apo_zh-cn/pay.md)** API, there is no need to set it again. In this case, the capture notification and authorization notification URLs remain the same.
-   If you have not set the asynchronous notification URL for the order in the _paymentNotifyUrl_ parameter when calling the [**pay**](https://docs.antom.com/ac/apo_zh-cn/pay.md) API and all your orders share a unified notification URL, you can set the webhook URL on [APO Dashboard](http://dashboard.alipay.com) through **Developer > Notification Address**. For detailed steps, refer to [Notification URL](https://docs.antom.com/ac/apo/notifications.md).

> **Note**:
>
> -   If you set the webhook URL both in the API and APO Dashboard, the one set in APO Dashboard takes precedence.
> -   For transactions paid with cards, Apple Pay, Google Pay or PayPal, APO will send capture results to you via the [**notifyCapture**](https://docs.antom.com/ac/apo/notify_capture.md) API. It is recommended to confirm the successful capture result before shipping.

The following is the notification request sample code:

```json
{
  "acquirerReferenceNo":"pay_6tmvamfcxp5ujbbfjeopyz6v7q",
  "result":{
    "resultStatus":"S",
    "resultCode":"SUCCESS",
    "resultMessage":"success."
  },
  "notifyType":"CAPTURE_RESULT",
  "captureTime":"2025-03-16T19:27:19-07:00",
  "paymentId":"20250317194010890100111600255689113",
  "captureRequestId":"G153202503171022523041",
  "captureId":"20250317194010890100111600255676857",
  "acquirerInfo":{
    "referenceRequestId":"2025031719031301000600278847294",
    "acquirerTransactionId":"act_yv3fchmu3bre3l3tui5y352yby",
    "acquirerMerchantId":"pc_6cpbmm5qderubjraxrygjehf5q",
    "acquirerName":"CHECKOUT"
  },
  "captureAmount":{
    "currency":"JPY",
    "value":"120"
  }
}
```

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 capture is successful. | You can proceed with the order and save the APO side _captureId_ information for future refund handling. |
| `F` | Indicates that the capture failed. | Use a different _captureRequestId_ and try again, or contact APO technical support. |

Table 3. Values of _resultStatus_ in the request

**2\. Verify asynchronous notifications**

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

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

```java
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 capture is successful or not. 

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

**Inquire about capture**

The asynchronous notification and the synchronous redirection can both fail to be received or implemented. We recommend that you inquire about the capture status by calling the [**inquiryPayment**](https://docs.antom.com/ac/apo/paymentri_online.md) API.

The following code shows how to call the [**inquiryPayment**](https://docs.antom.com/ac/apo/paymentri_online.md) API:

```java
public static void inquiryPayment() {
    AlipayPayQueryRequest alipayPayQueryRequest = new AlipayPayQueryRequest();

    // replace with your paymentRequestId
    alipayPayQueryRequest.setPaymentRequestId("yourPaymentRequestId");

    AlipayPayQueryResponse alipayPayQueryResponse = null;
    try {
        alipayPayQueryResponse = CLIENT.execute(alipayPayQueryRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
        // handle error condition
    }
}
```

The following code shows an example of a request:

```json
{
    "paymentRequestId": "PAY_202506*****942875"
}
```

In the response returned through the API, _transactions_ indicates the capture status. See the following table for details:

| **Parameter** | **Description** |
| --- | --- |
| _transactions.transationType_ | The value is `CAPTURE`. It indicates the capture status. |
| _transactions.transactionResult_ | The capture result. |
| _transactions.transactionResult.resultStatus_ | The capture status. The valid values are: - `S`: Indicates that the capture is successful. You can proceed with the capture status and save _captureId_ on the APO side for refunds. - `F`: Indicates that the capture failed. Please replace _capture__RequestId_ to try again. - `U`: Indicates that the capture is being processed. You can continue to inquire about the capture result. |

Table 4. Key parameters of _transactions_

The following sample codes show the returned values of _transactions_ in the response from the [**inquiryPayment**](https://docs.antom.com/ac/apo/paymentri_online.md) API under different scenarios:

#### Tab: The capture is successful

```json
{
    "transactions": [
        {
            "transactionType": "CAPTURE",
            "transactionStatus": "SUCCESS",
            "transactionRequestId": "test_test_test_XXXX",
            "transactionAmount": {
                "currency": "BRL",
                "value": "110"
            },
            "transactionId": "2022XXXXXXXX",
            "transactionResult": {
                "resultStatus": "S",
                "resultCode": "SUCCESS",
                "resultMessage": "success"
            }
        }
    ]
}
```

#### Tab: The capture failed

```json
{
    "transactions": [
        {
            "transactionType": "CAPTURE",
            "transactionStatus": "FAIL",
            "transactionRequestId": "test_test_test_XXXX",
            "transactionAmount": {
                "currency": "BRL",
                "value": "110"
            },
            "transactionTime": "2022-09-29T07:13:50-07:00",
            "transactionId": "2022XXXXXXXX",
            "transactionResult": {
                "resultStatus": "F",
                "resultCode": "PROCESS_FAIL",
                "resultMessage": "General business failure. No retry."
            }
        }
    ]
}
```

#### Tab: The capture is being processed

```json
{
    "transactions": [
        {
            "transactionType": "CAPTURE",
            "transactionStatus": "PROCESSING",
            "transactionRequestId": "test_test_test_XXXX",
            "transactionAmount": {
                "currency": "BRL",
                "value": "110"
            },
            "transactionId": "2022XXXXXXXX",
            "transactionResult": {
                "resultStatus": "U",
                "resultCode": "PAYMENT_IN_PROCESS",
                "resultMessage": "payment in process"
            }
        }
    ]
}

```

> **Common Questions**
>
> **Q: Will the asynchronous notification be re-sent?**
>
> A: Yes, the asynchronous notification will be re-sent automatically within 24 hours for the following cases:
>
> -   If you didn't receive the asynchronous notification due to network reasons.
> -   If you receive an asynchronous notification from APO, but you didn't make a response to the notification in the [Sample code](https://docs.antom.com/ac/apo/notifications.md#OqpVS) format.
>
> The notification can be resent up to 8 times or until a correct response is received to terminate delivery. The sending intervals are as follows: 0 minutes, 2 minutes, 10 minutes, 10 minutes, 1 hour, 2 hours, 6 hours, and 15 hours.
>
> **Q:** **Does the capture request support retrying the original request?**
>
> A: Yes, it is supported. The [**capture**](capture_pay) API implements an idempotency mechanism based on the _captureRequestId_.
>
> -   If the initial response is `F` (failure), even if the request is retried, the result will remain as `F` and will not change.
> -   If the initial response is `U` (processing), even if the request is retried, the system will return the final processed status, which could be either `S` (success) or `F` (failure).
>
> **Q:** **What are t****he key parameters in the inquiry that I need to use?**
>
> A: Pay attention to the following key parameter:
>
> -   _transactionResult.resultStatus_: You need to determine the capture result based on this parameter.