请款
您可以使用以下两种方式来请款:
- 全额自动请款
- 全额手动请款
注意:
- 卡支付场景下,建议您以请款成功作为发货依据。
- 对于 Antom 收单机构,韩国认证卡不支持手动请款;对于 2C2P 收单机构,韩国认证卡不需要请款。
- 对于 Antom 收单机构,若商家在买家授权支付成功后 7 天还未请款,那么交易会自动取消。对于其他收单机构,请根据各机构的请款规则进行处理。
全额自动请款
您需将 支付 或 支付会话创建 接口中的 paymentFactor.captureMode 参数的值设置为 AUTOMATIC
,买家授权完成后由 APO 替您立刻发起请款,并通过通知形式将请款结果发送给您。
全额手动请款
您需将 支付 或 支付会话创建 接口中的 paymentFactor.captureMode 参数的值设置为 MANUAL
,同时需集成 请款 接口,在买家授权后自行发起请款,并通过通知形式获取最终的请款结果。
请款集成步骤
请按照以下步骤开始集成:
- 发起请款请求
- 获取请款结果
步骤 1:发起请款请求
以下示例代码展示了如何调用 请款 接口:
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. 请款 接口请求关键参数
以下为一个请款请求的示例代码:
{
"paymentId": "20220919194010890100111740275820195",
"captureRequestId": "capture_cangxi_lj_20220920_005914_845",
"captureAmount": {
"currency": "HKD",
"value": "10"
}
}
以下代码展示了一个响应的示例,其中包含以下参数:
{
"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 还会额外通过 请款通知 接口发送请款结果给您。您需要依赖请款成功作为发货依据。
以下代码展示了通知请求的示例:
{
"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 发送的请款通知进行验签。
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);
}
}
您无需对响应通知结果做加签处理,但是对于每个通知请求均需按以下固定格式响应,与订单支付成功与否无关。
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
}
}
查询请款
请款 请求的响应及异步通知均有无法触达或延迟的可能性;建议您在服务端通过 支付结果查询 接口主动查询请款状态。
以下代码展示了如何调用 支付结果查询 接口:
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();
// 处理错误情况
}
}
以下代码展示了一个请求报文的示例:
{
"paymentRequestId": "PAY_202506*****942875"
}
该接口响应中的 transactions 字段的值为请款状态:
字段名 | 说明 |
transactions.transationType | 值为 CAPTURE ,代表为请款的状态。 |
transactions.transactionResult | 请款结果。 |
transactions.transactionResult.resultStatus | 请款状态。有效值为:
|
表 4. 主动查询响应中 transaction 字段关键信息说明
以下示例展示了 支付结果查询 接口的响应中,transactions 字段在不同情况下的返回值:
{
"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:您需要根据此参数来判断请款状态。