请款

您可以使用以下两种方式来请款:

  • 全额自动请款
  • 全额手动请款

注意

  • 卡支付场景下,建议您以请款成功作为发货依据。
  • 对于 Antom 收单机构,韩国认证卡不支持手动请款;对于 2C2P 收单机构,韩国认证卡不需要请款。
  • 对于 Antom 收单机构,若商家在买家授权支付成功后 7 天还未请款,那么交易会自动取消。对于其他收单机构,请根据各机构的请款规则进行处理。

全额自动请款

您需将 支付支付会话创建 接口中的 paymentFactor.captureMode 参数的值设置为 AUTOMATIC,买家授权完成后由 APO 替您立刻发起请款,并通过通知形式将请款结果发送给您。

全额手动请款

您需将 支付支付会话创建 接口中的 paymentFactor.captureMode 参数的值设置为 MANUAL,同时需集成 请款 接口,在买家授权后自行发起请款,并通过通知形式获取最终的请款结果。

请款集成步骤

请按照以下步骤开始集成:

  1. 发起请款请求
  2. 获取请款结果

步骤 1:发起请款请求服务端

以下示例代码展示了如何调用 请款 接口:

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

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

    // 替换为您的 captureRequestId
    String captureRequestId = UUID.randomUUID().toString();
    alipayCaptureRequest.setCaptureRequestId(captureRequestId);

    // 替换为您的 paymentId
    alipayCaptureRequest.setPaymentId("20240101123456789XXXX");

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

调用 请款 接口时注意以下关键参数:

字段名

是否必填

说明

captureRequestId

在商户侧唯一的请款 ID。

paymentId

授权返回的 APO 侧的订单 ID。

captureAmount.value

请款金额,应小于或等于授权的金额。

captureAmount.currency

请款币种。需支付 接口中的支付金额的币种(paymentAmount.currency)保持一致。

表 1. 请款 接口请求关键参数

以下为一个请款请求的示例代码:

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

以下代码展示了一个响应的示例,其中包含以下参数:

copy
{
  "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"
  }
}

下表展示了响应报文中 result.resultStatus 字段可能返回的值,请您根据指引进行处理:

result.resultStatus

信息下一步操作
S表示请款成功。

您可推进订单状态,同时存储 APO 侧的 captureId 用于后续退款。

F

表示请款失败。

请您更换 captureRequestId 再次请款或联系 APO 技术支持。
U

表示请款正在受理中。

请款正在受理中,您可选择主动调用 支付结果查询 接口获取请款结果,或者等待请款结果通知。

表 2. 请款响应中 result.resultStatus 的参数值含义

注意:如果您未收到响应报文,可能是网络超时所致。您可选择主动调用 支付结果查询 接口获取请款结果,或者等待请款结果通知。

步骤 2:获取请款结果服务端

在买家完成支付或支付超时后,APO 会通过服务器交互将相应的支付结果发送给您,您可以通过以下方法之一获取请款结果:

  • 接收异步通知
  • 查询结果

设置异步通知

1. 设置接收通知的 webhook URL

您可以选择以下两种方法中的一种来设置接受通知的 webhook URL:

  • 在调用 支付 接口时,paymentNotifyUrl 字段中已设置过该笔订单的异步通知 URL,则无需再次设置,此时请款通知和授权通知地址保持一致。
  • 在调用 支付 接口时,pay.request.paymentNotifyUrl 字段没有设置该笔订单的异步通知 URL且您的所有订单都有一个统一的通知 URL,那您则可以 APO Dashboard开发者 > 通知地址 中设置 webhook URL。

注意

  • 若您在接口和 APO Dashboard 中都设置了 webhook URL,则以 APO Dashboard 中设置的为准。
  • 当支付方式是卡、Apple Pay、Google Pay、PayPal 时,APO 还会额外通过 请款通知 接口发送请款结果给您。您需要依赖请款成功作为发货依据。

以下代码展示了通知请求的示例:

copy
{
  "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"
  }
}

您可能会收到请求报文中 result.resultStatus 字段的不同值,请您根据下表指引进行处理:

result.resultStatus

信息下一步操作
S表示请款成功。

您可推进订单状态,同时存储 APO 侧的 captureId 用于后续退款。

F

表示请款失败。

请您更换 captureRequestId 再次请款或联系 APO 技术支持。

表 3. 通知请求中 result.resultStatus 的参数值含义

2. 异步通知验签

若您收到 APO 的异步通知,需要您在返回中按照示例代码格式返回响应,但无需做加签处理。

您需要对 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) {

        // 从 http 请求中获取所需参数
        String requestUri = request.getRequestURI();
        String requestMethod = request.getMethod();

        // 从请求头中获取所需参数
        String requestTime = request.getHeader("request-time");
        String clientId = request.getHeader("client-id");
        String signature = request.getHeader("signature");

        Result result;
        AlipayResponse response = new AlipayResponse();

        try {
            // 通知验签
            boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId, requestTime, signature, notifyBody, SERVER_PUBLIC_KEY);
            if (!verifyResult) {
                throw new RuntimeException("Invalid notify signature");
            }

            // 反序列化通知主体
            
            // 根据通知结果更新订单状态

            // 响应服务端已接收通知
            result = new Result("SUCCESS", "success", ResultStatusType.S);

        } catch (Exception e) {
            String errorMsg = e.getMessage();
            // 处理错误情况
            result = new Result("ERROR", errorMsg, ResultStatusType.F);
        }
        response.setResult(result);
        return ResponseEntity.ok().body(response);
    }

}

您无需对响应通知结果做加签处理,但是对于每个通知请求均需按以下固定格式响应,与订单支付成功与否无关。

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

查询请款

请款 请求的响应及异步通知均有无法触达或延迟的可能性;建议您在服务端通过 支付结果查询 接口主动查询请款状态。

以下代码展示了如何调用 支付结果查询 接口:

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

    // 替换为您的 paymentRequestId
    alipayPayQueryRequest.setPaymentRequestId("yourPaymentRequestId");

    AlipayPayQueryResponse alipayPayQueryResponse = null;
    try {
        alipayPayQueryResponse = CLIENT.execute(alipayPayQueryRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
        // 处理错误情况
    }
}

以下代码展示了一个请求报文的示例:

copy
{
    "paymentRequestId": "PAY_202506*****942875"
}

该接口响应中的 transactions 字段的值为请款状态:

字段名说明
transactions.transationType值为 CAPTURE,代表为请款的状态。
transactions.transactionResult请款结果。
transactions.transactionResult.resultStatus

请款状态。有效值为:

  • S:表示请款成功。您可推进请款状态,同时存储 APO 侧的 captureId 用于后续退款。
  • F:表示请款失败。请更换 captureRequestId 再次请款。
  • U:表示请款进行中,您可以继续查询。

表 4. 主动查询响应中 transaction 字段关键信息说明

以下示例展示了 支付结果查询 接口的响应中,transactions 字段在不同情况下的返回值:

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

常见问题

问:异步通知会被重新发送吗?

答:是的,对于以下情况,异步通知会在 24 小时内自动重新发送:

  • 由于网络原因未收到异步通知。
  • 您收到来自 APO 的异步通知后,没有按照处理通知的示例代码格式对通知做出响应。

通知至多重发 8 次或直至收到正确响应终止发送。发送间隔如下:0 分钟,2 分钟,10 分钟,10 分钟,1 小时,2 小时,6 小时,15 小时。

问:请款调用是否支持原请求重试?

答:支持。我们的请款接口基于 captureRequestId 字段实现幂等性机制。

  • 如果首次返回 F(失败),那么即使再次调用,结果仍会是 F,不会改变。
  • 如果首次返回 U(处理中),那么再次调用时,系统会返回处理后的最终状态:可能是 S(成功)或者 F(失败)。

问:我在查询中需要使用哪些关键参数?

答:请注意以下关键参数:

  • transactions.transactionResult.resultStatus您需要根据此参数来判断请款状态。