集成快捷支付(API)
Antom EasySafePay 是一款专注于小额高频支付场景的极简支付解决方案。买家可在首次支付时完成钱包绑定或直接支付。后续支付时无需输入密码即可一次点击完成支付。
该方案依托行业领先的智能风控系统、动态轮询技术和支付失败挽回策略,在确保交易安全的同时将支付成功率提升至行业顶尖水平,实现了买家支付体验、商户转化率和平台生态价值的三方共赢。
本文主要介绍如何通过 API 方式集成 EasySafePay 产品。
用户体验
各支付方式在 PC 端和移动端的用户体验存在差异,具体交互方式详见以下表格及用户体验图:
Web
WAP
App
以下分别为电子钱包和网银转账两种支付类别在桌面浏览器上(Web)的用户体验图。
电子钱包
网银转账
电子钱包场景下,首次支付和后续支付体验图如下。
首次支付
后续支付
首次支付时买家需要完成支付授权流程以确保后续免密支付。

后续支付若需要买家参与,买家仅需提交订单即可完成免密支付。若不需要买家参与,您直接从后台发起支付请求即可。

网银转账支付场景体验图如下所示:
首次支付
后续支付
首次支付时买家需要完成支付授权流程以确保后续免密支付。

后续支付若需要买家参与,买家仅需提交订单即可完成免密支付。若不需要买家参与,您直接从后台发起支付请求即可。

以下分别为电子钱包和网银转账两种支付类别在移动端浏览器(WAP)上的用户体验图。
电子钱包
网银转账
电子钱包场景下,首次支付和后续支付体验图如下。
首次支付
后续支付
首次支付时,系统将引导买家在商户页面或支付方式侧完成交易。买家完成授权后,后续支付可以免密支付。
在商户页面支付
跳转至支付方式应用程序支付


后续支付若需要买家参与,买家仅需提交订单即可完成免密支付。若不需要买家参与,您直接从后台发起支付请求即可。

网银转账场景下,首次支付和后续支付体验图如下。
首次支付
后续支付
首次支付时买家需要完成支付授权流程以确保后续免密支付。

后续无需重新绑定账号即可完成支付。

以下分别为电子钱包和网银转账两种支付类别在移动端(App)的用户体验图。
电子钱包
网银转账
电子钱包场景下,首次支付和后续支付体验图如下。
首次支付
后续支付
首次支付时,系统将引导买家在商户页面或支付方式侧完成交易。买家完成授权后,后续支付可以免密支付。
在商户页面支付
跳转至支付方式应用程序支付


后续支付若需要买家参与,买家仅需提交订单即可完成免密支付。若不需要买家参与,您直接从后台发起支付请求即可。

网银转账场景下,首次支付和后续支付体验图如下。
首次支付
后续支付
首次支付时买家需要完成支付授权流程以确保后续免密支付。

后续无需重新绑定账号即可完成支付。

支付流程
首次支付
后续支付

- 买家进入商户收银台页面
- 买家选择支付方式后提交支付请求
- 创建支付请求
买家选择支付方式并提交订单后,商户服务端根据支付方式、金额、币种、商品等交易信息,调用 pay(令牌支付) 接口发起支付请求。 - 处理支付推进链接
商户客户端跳转至支付请求返回的 URL 页面,或唤起相关应用程序完成授权支付。 - 获取授权结果
当授权成功时, Antom 会通过 notifyAuthorization 接口向您发送异步通知。 - 获取支付结果
通过以下两种方法获取支付结果:
- 异步通知:在 pay(令牌支付) 接口中指定 paymentNotifyUrl 或门户设置接收异步通知的地址。当支付完成后,Antom 会使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口检查支付状态。

- 买家进入商户收银台页面
- 买家选择支付方式后提交支付请求
- 创建支付请求
在获得买家授权后,您可以直接调用 pay(令牌支付) 接口发起支付。 - 买家完成风险验证
当交易出现风险时,需要跳转到前端页面完成验证。若是商家从后台直接发起订阅扣款,则不会出现验证页面。
- 获取支付结果
通过以下两种方法获取支付结果:
- 异步通知:在 pay(令牌支付) 接口中指定 paymentNotifyUrl 或门户设置接收异步通知的地址。当支付完成后,Antom 会使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口检查支付状态。
集成准备
- 已获得 client ID。
- 已完成密钥配置。
- 已完成异步通知接收地址的配置。
- 集成服务端 SDK 资源包,并完成接口库安装及请求示例初始化。具体操作请参阅服务端 SDK。
集成步骤
开始集成,请按照以下步骤操作:
- 创建支付请求
- 获取跳转支付推进链接
- 获取授权和支付结果
步骤 1:创建支付请求
首次支付和后续支付调用接口参数说明:
注意:
- PayPay Smart Payment 集成流程有所不同,具体步骤请参考集成 PayPay Smart Payment 支付。
- Express Bank Transfer 的首次支付与后续支付使用相同的传参格式,买家只需在支付页面输入手机号即可完成支付。
首次支付时传入 order.buyer.buyerPhoneNo 可自动回填买家支付方式账号至支付页面,避免手动输入操作。以下是传入和未传入的体验对比图:
传入支付方式登录账号
未传入支付方式登录账号
当传入支付方式账号时,买家进入授权支付流程或选择单笔支付。
授权并支付
单笔支付
开启 Enable One-Click Payment 按钮,首次支付完成授权即可开启免密支付,后续交易方便快捷。

关闭 Enable One-Click Payment 按钮,跳转至支付方式侧进行单笔支付。

当未传入支付方式账号时, 页面将引导买家跳转至支付方式侧进行授权。

以下是首次支付和后续支付两种不同场景集成代码示例:
首次支付
后续支付
首次支付
@PostMapping("/v1/payments/pay")
public ResponseEntity<ApiResponse> pay(@RequestBody PaymentVO payment) {
AmsPayRequest request = new AmsPayRequest();
request.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
request.setPaymentRequestId(paymentRequestId);
// 转换金额单位(实际使用中,金额应在服务端计算)
// 详情请参考: https://docs.antom.com/ac/ref/cc
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency),
new BigDecimal(payment.amountValue)).getAmountMinorLong();
// 设置 paymentAmount
Amount paymentAmount = Amount.builder()
.currency(payment.currency)
.value(String.valueOf(amountMinorLong))
.build();
request.setPaymentAmount(paymentAmount);
// 设置 settlementStrategy
// 替换为您现有的结算货币
SettlementStrategy settlementStrategy = SettlementStrategy.builder()
.settlementCurrency("USD")
.build();
request.setSettlementStrategy(settlementStrategy);
// 设置 paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder()
.paymentMethodType(payment.paymentMethodType)
.build();
User loginUser = users.get(payment.getUserId());
if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
// 买家已授权,使用 token 走代扣
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
paymentMethod.setPaymentMethodId(accessToken);
} else {
// 买家未授权,设置 agreementInfo 走签约流程
String authState = UUID.randomUUID().toString();
AgreementInfo agreementInfo = AgreementInfo.builder()
.authState(authState)
.build();
request.setAgreementInfo(agreementInfo);
// 保存与 authState 对应的 paymentMethodType
authStatePayment.put(authState, payment);
}
request.setPaymentMethod(paymentMethod);
// 设置 env(环境信息,用于风控)
Env env = Env.builder()
.osType(payment.getOsType())
.terminalType(payment.getTerminalType())
.deviceId(payment.getDeviceId())
.clientIp(payment.getClientIp())
.deviceTokenId(payment.getDeviceTokenId())
.build();
request.setEnv(env);
// 设置 goods(商品明细)
List<Goods> goodsList = payment.getGoodsList().stream()
.map(g -> Goods.builder()
.referenceGoodsId(g.getReferenceGoodsId())
.goodsName(g.getGoodsName())
.quantity(g.getQuantity())
.price(Amount.builder()
.currency(payment.currency)
.value(g.getPriceValue())
.build())
.build())
.collect(Collectors.toList());
// 设置 shipping(物流信息)
Shipping shipping = Shipping.builder()
.shippingName(ShippingName.builder()
.firstName(payment.getShippingFirstName())
.lastName(payment.getShippingLastName())
.build())
.shippingAddress(ShippingAddress.builder()
.region(payment.getShippingRegion())
.state(payment.getShippingState())
.city(payment.getShippingCity())
.address1(payment.getShippingAddress1())
.address2(payment.getShippingAddress2())
.zipCode(payment.getShippingZipCode())
.build())
.shippingCarrier(payment.getShippingCarrier())
.shippingPhoneNo(payment.getShippingPhoneNo())
.build();
// 设置 buyer(买家信息)
Buyer buyer = Buyer.builder()
.referenceBuyerId(loginUser.getReferenceBuyerId())
.buyerName(BuyerName.builder()
.firstName(loginUser.getFirstName())
.lastName(loginUser.getLastName())
.build())
.buyerPhoneNo(loginUser.getPhoneNumber())
.buyerEmail(loginUser.getEmail())
.build();
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置 order(订单信息,含商品明细、物流、买家)
Amount orderAmount = Amount.builder()
.currency(payment.currency)
.value(String.valueOf(amountMinorLong))
.build();
Order order = Order.builder()
.referenceOrderId(orderId)
.orderDescription(payment.getOrderDescription())
.orderAmount(orderAmount)
.goods(goodsList)
.shipping(shipping)
.buyer(buyer)
.build();
request.setOrder(order);
// 替换为您的通知 url
// 或配置您的通知 url: https://dashboard.antom.com/global-payments/developers/iNotify
request.setPaymentNotifyUrl("https://merchant.com/notify/payment-result");
// 替换为您的跳转 url
request.setPaymentRedirectUrl(
"https://merchant.com/payment/result?paymentRequestId=" + paymentRequestId);
AmsPayResponse amsPayResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("pay request: " + JSON.toJSONString(request));
amsPayResponse = CLIENT.execute(request, AmsPayResponse.class);
System.out.println("pay response: " + JSON.toJSONString(amsPayResponse));
System.out.println("pay request cost time: " + (System.currentTimeMillis() - startTime) + "ms");
} catch (AlipayApiException e) {
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
}
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), amsPayResponse));
}请求报文示例:
{
"order": {
"orderAmount": {
"currency": "HKD",
"value": 100
},
"referenceOrderId": "ORD_2024040512345",
"orderDescription": "iPhone 15 Pro Monthly Subscription",
"goods": [
{
"referenceGoodsId": "G_001",
"goodsName": "iPhone 15 Pro",
"quantity": 1,
"price": {
"currency": "HKD",
"value": 100
}
}
],
"shipping": {
"shippingName": {
"firstName": "John",
"lastName": "Doe"
},
"shippingAddress": {
"region": "US",
"state": "CA",
"city": "San Francisco",
"address1": "123 Tech Street",
"address2": "Apt 4B",
"zipCode": "94107"
},
"shippingCarrier": "FedEx",
"shippingPhoneNo": "+1-415-555-1234"
},
"buyer": {
"referenceBuyerId": "BUYER_88118999",
"buyerName": {
"firstName": "John",
"lastName": "Doe"
},
"buyerPhoneNo": "66622222",
"buyerEmail": "john.doe@example.com"
}
},
"env": {
"osType": "IOS",
"terminalType": "APP",
"deviceId": "deviceIdxxxxxxx",
"clientIp": "192.168.111.111",
"deviceTokenId": "deviceTokenIdxxxxxxxx"
},
"paymentRequestId": "PAYMENT_20251110121228651_AUTO",
"paymentAmount": {
"currency": "HKD",
"value": 100
},
"settlementStrategy": {
"settlementCurrency": "USD"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "https://merchant.com/notify/payment-result",
"paymentRedirectUrl": "https://kademo.intlalipay.cn/melitigo/Test_114.html",
"productCode": "AGREEMENT_PAYMENT",
"agreementInfo":{
"authState":"sign_no_xxxxx111111x01001"
}
}响应报文示例:
{
"actualPaymentAmount": {
"currency": "HKD",
"value": "100"
},
"normalUrl": "https://checkout.antom.com/easysafepay/1.39.0/pages/api-portal/index.html?paymentMethodCategoryType=WALLET&sessionData=vxA9kkY8yysEoUhFyy%2BEvM17vV72yntAcqJGeMF1PETOU9fJtoSUls3s0vdS1YouYbWEl8gHHEaWPO0Xh%2FT%2BJg%3D%3D%26%26SG%26%26188&locale=en-US&productScene=EASY_PAY&productSceneVersion=2.0",
"paymentActionForm": "{"method":"GET","paymentActionFormType":"RedirectActionForm","redirectUrl":"https://checkout.antom.com/easysafepay/1.39.0/pages/api-portal/index.html?paymentMethodCategoryType=WALLET&sessionData=vxA9kkY8yysEoUhFyy%2BEvM17vV72yntAcqJGeMF1PETOU9fJtoSUls3s0vdS1YouYbWEl8gHHEaWPO0Xh%2FT%2BJg%3D%3D%26%26SG%26%26188&locale=en-US&productScene=EASY_PAY&productSceneVersion=2.0"}",
"paymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentCreateTime": "2025-11-10T00:35:03-08:00",
"paymentId": "20251110194010900000188350227845338",
"paymentRequestId": "PAYMENT_20251110163502455_AUTO",
"redirectActionForm": {
"method": "GET",
"redirectUrl": "https://checkout.antom.com/easysafepay/1.39.0/pages/api-portal/index.html?paymentMethodCategoryType=WALLET&sessionData=vxA9kkY8yysEoUhFyy%2BEvM17vV72yntAcqJGeMF1PETOU9fJtoSUls3s0vdS1YouYbWEl8gHHEaWPO0Xh%2FT%2BJg%3D%3D%26%26SG%26%26188&locale=en-US&productScene=EASY_PAY&productSceneVersion=2.0"
},
"result": {
"resultCode": "PAYMENT_IN_PROCESS",
"resultMessage": "payment in process",
"resultStatus": "U"
}
}请根据返回的 result.resultStatus 参数值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请关闭当前交易或重新更换 authState 和 paymentRequestId 后再次下单。
后续支付
@PostMapping("/v1/payments/pay")
public ResponseEntity<ApiResponse> pay(@RequestBody PaymentVO payment) {
AmsPayRequest request = new AmsPayRequest();
request.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
request.setPaymentRequestId(paymentRequestId);
// 转换金额单位(实际使用中,金额应在服务端计算)
// 详情请参考: https://docs.antom.com/ac/ref/cc
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency),
new BigDecimal(payment.amountValue)).getAmountMinorLong();
// 设置 paymentAmount
Amount paymentAmount = Amount.builder()
.currency(payment.currency)
.value(String.valueOf(amountMinorLong))
.build();
request.setPaymentAmount(paymentAmount);
// 设置 settlementStrategy
// 替换为您现有的结算货币
SettlementStrategy settlementStrategy = SettlementStrategy.builder()
.settlementCurrency("USD")
.build();
request.setSettlementStrategy(settlementStrategy);
// 设置 paymentMethod(代扣场景:使用已有的 paymentMethodId)
User loginUser = users.get(payment.getUserId());
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
PaymentMethodMetadata metadata = PaymentMethodMetadata.builder()
.recurringType("SCHEDULED") // 用户不参与扣款时传入 SCHEDULED,用户参与场景不需要传入
.build();
PaymentMethod paymentMethod = PaymentMethod.builder()
.paymentMethodType(payment.paymentMethodType)
.paymentMethodId(accessToken)
.paymentMethodMetadata(metadata)
.build();
request.setPaymentMethod(paymentMethod);
// 设置 env(环境信息,用于风控)
Env env = Env.builder()
.osType(payment.getOsType())
.terminalType(payment.getTerminalType())
.deviceId(payment.getDeviceId())
.clientIp(payment.getClientIp())
.deviceTokenId(payment.getDeviceTokenId())
.build();
request.setEnv(env);
// 设置 goods(商品明细)
List<Goods> goodsList = payment.getGoodsList().stream()
.map(g -> Goods.builder()
.referenceGoodsId(g.getReferenceGoodsId())
.goodsName(g.getGoodsName())
.quantity(g.getQuantity())
.price(Amount.builder()
.currency(payment.currency)
.value(g.getPriceValue())
.build())
.build())
.collect(Collectors.toList());
// 设置 shipping(物流信息)
Shipping shipping = Shipping.builder()
.shippingAddress(ShippingAddress.builder()
.region(payment.getShippingRegion())
.state(payment.getShippingState())
.city(payment.getShippingCity())
.address1(payment.getShippingAddress1())
.address2(payment.getShippingAddress2())
.zipCode(payment.getShippingZipCode())
.build())
.build();
// 设置 buyer(买家信息)
Buyer buyer = Buyer.builder()
.referenceBuyerId(payment.getReferenceBuyerId())
.buyerName(BuyerName.builder()
.firstName(payment.getBuyerFirstName())
.lastName(payment.getBuyerLastName())
.build())
.buyerPhoneNo(payment.getBuyerPhoneNo())
.buyerEmail(payment.getBuyerEmail())
.build();
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置 order(订单信息,含商品明细、物流、买家)
Amount orderAmount = Amount.builder()
.currency(payment.currency)
.value(String.valueOf(amountMinorLong))
.build();
Order order = Order.builder()
.referenceOrderId(orderId)
.orderDescription(payment.getOrderDescription())
.orderAmount(orderAmount)
.goods(goodsList)
.shipping(shipping)
.buyer(buyer)
.build();
request.setOrder(order);
// 替换为您的通知 url
// 或配置您的通知 url: https://dashboard.antom.com/global-payments/developers/iNotify
request.setPaymentNotifyUrl("https://kademo.intlalipay.cn/payments/notifySuccess");
// 替换为您的跳转 url
request.setPaymentRedirectUrl(
"https://kademo.intlalipay.cn/melitigo/Test_114.html");
AmsPayResponse amsPayResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("pay request: " + JSON.toJSONString(request));
amsPayResponse = CLIENT.execute(request, AmsPayResponse.class);
System.out.println("pay response: " + JSON.toJSONString(amsPayResponse));
System.out.println("pay request cost time: " + (System.currentTimeMillis() - startTime) + "ms");
// 代扣场景:支付结果同步返回
// resultStatus=S 表示支付成功,无需跳转收银台
if ("S".equals(amsPayResponse.getResult().getResultStatus())) {
System.out.println("Payment SUCCESS, paymentId: " + amsPayResponse.getPaymentId()
+ ", paymentTime: " + amsPayResponse.getPaymentTime());
}
} catch (AlipayApiException e) {
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
}
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), amsPayResponse));
}请求报文示例:
{
"order": {
"orderAmount": {
"currency": "HKD",
"value": 100
},
"referenceOrderId": "ORD_2024040512345",
"orderDescription": "iPhone 15 Pro Monthly Subscription",
"goods": [
{
"referenceGoodsId": "G_001",
"goodsName": "iPhone 15 Pro",
"quantity": 1,
"price": {
"currency": "HKD",
"value": 100
}
}
],
"shipping": {
"shippingAddress": {
"region": "US",
"state": "CA",
"city": "San Francisco",
"address1": "123 Tech Street",
"address2": "Apt 4B",
"zipCode": "94107"
}
},
"buyer": {
"referenceBuyerId": "BUYER_88118999",
"buyerName": {
"firstName": "John",
"lastName": "Doe"
},
"buyerPhoneNo": "66622222",
"buyerEmail": "john.doe@example.com"
}
},
"env": {
"osType": "IOS",
"terminalType": "APP",
"deviceId": "deviceIdxxxxxxx",
"clientIp": "192.168.111.111",
"deviceTokenId": "deviceTokenIdxxxxxxxx"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_HK",
"paymentMethodId":"xxxxxxxx",
"paymentMethodMetadata":{
"recurringType":"SCHEDULED" //买家不参与的情况下需要传入,买家参与场景不需要传入
}
},
"settlementStrategy": {
"settlementCurrency": "USD"
},
"paymentNotifyUrl": "https://kademo.intlalipay.cn/payments/notifySuccess",
"paymentRedirectUrl": "https://kademo.intlalipay.cn/melitigo/Test_114.html",
"paymentRequestId": "PAY_20251110143957765",
"productCode": "AGREEMENT_PAYMENT"
}响应报文示例:
{
"actualPaymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentCreateTime": "2025-11-05T23:03:16-08:00",
"paymentId": "202511061940108001001888********",
"paymentRequestId": "PAYMENT_20251106150314003_AUTO",
"paymentTime": "2025-11-05T23:03:18-08:00",
"pspCustomerInfo": {
"pspCustomerId": "208812211210000",
"pspName": "ALIPAY_HK"
},
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}请根据返回的 result.resultStatus 参数的值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请保持 paymentRequestId 不变重新调用接口以解决问题。如果问题未解决,请联系 Antom 技术支持。
常见问题
问:请求参数的值可以使用中文字符吗?
答:为了避免某些支付方式的不兼容,不要在请求的参数中使用中文字符。
问:如何设置接收支付通知的链接?
答:在 pay(令牌支付) 接口中指定参数 paymentNotifyUrl,以接收支付结果的异步通知(notifyPayment),或者在 Antom Dashboard 中配置接收链接。如果请求和 Antom Dashboard 中都指定了链接,请求中指定的值优先。
问:paymentAmount 和 orderAmount 的区别是什么?
答:paymentAmount 是指支付金额,orderAmount 是指订单金额。实际支付金额以 paymentAmount 为准。
步骤 2:获取跳转支付推进链接
商户服务端拿到 Antom 返回的支付推进链接后,将该地址传递给前端,由商户前端跳转至支付方式页面。
以下为商户前端加载支付推进链接的示例代码:
Web
WAP
iOS
Android
if (URL != null) {
window.open(URL, '_blank');
}window.location.href = URL;if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:Url] options:@{} completionHandler:nil];
}else{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:Url]];
}try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(URL));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// use the startActivity function to redirect to the wallet app
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}下图为支付方式收银台页面的效果图:
首次支付
后续支付


在某些场景下,风控可能会要求买家进行 OTP 核身。
步骤 3:获取授权和支付结果
回跳支付结果页面
注意:并不是所有情况都支持回跳,例如买家操作或者网络原因无法回跳。
获取授权和支付结果
首次支付将返回授权及支付结果,后续支付仅返回支付结果。以下是常见场景:
获取授权结果
获取支付结果
- 配置接收异步授权通知的 webhook URL:按照 Antom Dashboard > 开发者 > 通知地址路径,为 alipay.ams.authorizations.notify 接口增加通知地址。具体操作请参阅通知地址。
以下是异步授权通知请求的代码示例:
{
"accessToken": "28288803001319861727421828000Cv96OFlYoi17100****",
"accessTokenExpiryTime": 2145916817000,
"authState": "36a38e87-0453-495e-ad17-b46553b918da",
"authorizationNotifyType": "TOKEN_CREATED",
"userLoginId": "852-91****67",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}根据授权结果通知请求中 result.resultStatus 的值(仅返回
S
)进行处理。S
:表示授权成功,并返回以下参数:下表为各支付方式的令牌有效期:
- Antom 发送的通知结果由 Antom 加签,故建议您验证签名以确认通知由 Antom 发送。参考以下代码示例对授权通知进行验签:
@PostMapping("/receiveAuthNotify")
@ResponseBody
public Result receiveAuthNotify(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");
try {
// 验证通知签名
boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId,
requestTime, signature, notifyBody, ANTOM_PUBLIC_KEY);
if (!verifyResult) {
throw new RuntimeException("Invalid notify signature");
}
// 反序列化通知体
AlipayAuthNotify authNotify = JSON.parseObject(notifyBody,AlipayAuthNotify.class);
if (authNotify != null && "SUCCESS".equals(authNotify.getResult().getResultCode())
&& "TOKEN_CREATED".equals(authNotify.getAuthorizationNotifyType())) {
// 保存买家 PaymentMethodType 与 accessToken 的对应关系
PaymentVO payment = authStatePayment.get(authNotify.getAuthState());
User user = users.get(payment.getUserId());
user.getPaymentMethodTypeAccessToken().put(payment.getPaymentMethodType(), authNotify.getAccessToken());
return Result.builder().resultCode("SUCCESS").resultMessage("success.").resultStatus(ResultStatusType.S).build();
}
// 其他类型的通知
} catch (Exception e) {
return Result.builder().resultCode("FAIL").resultMessage("fail.").resultStatus(ResultStatusType.F).build();
}
return Result.builder().resultCode("SYSTEM_ERROR").resultMessage("system error.").resultStatus(ResultStatusType.F).build();
}- 收到通知后,您无需对响应通知结果做加签处理,但是对于每个通知请求均需按以下固定格式响应,与授权成功与否无关。
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
}
}首次支付或后续支付完成后,可通过以下方式获取支付结果:
- 接收异步通知:接收 Antom 服务端发送的支付结果
- 查询支付结果:调用 inquiryPayment 接口获取支付状态
接收异步通知
查询支付结果
- 设置接收通知的 Webhook URL:
完成支付或支付失败时,Antom 会向您设置的 webhook URL 发送异步通知,您可以选择以下两种方法中的一种来设置接收通知的 webhook URL:
- 订单级通知配置:通过 pay(令牌支付)接口请求中的 paymentNotifyUrl 参数为每笔订单指定独立的通知 URL。
- 商户级通知配置:登陆 Antom Dashboard > 开发者 > 通知地址,为 alipay.ams.payments.payNotify 接口增加通知地址。具体操作请参阅通知地址。
注意:如果以上两种方式您都配置了通知地址,则优先以接口设置为准。
以下是支付结果异步通知请求的代码示例:
{
"actualPaymentAmount": {
"currency": "HKD",
"value": "98080"
},
"customsDeclarationAmount": {},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentCreateTime": "2024-09-27T00:23:36-07:00",
"paymentId": "202409271940108001001881E0211235544",
"paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a792a",
"paymentTime": "2024-09-27T00:23:46-07:00",
"pspCustomerInfo": {
"pspCustomerId": "20881221121****",
"pspName": "ALIPAY_HK"
},
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}下表展示了支付结果的异步通知中 result.resultStatus 参数可能返回的值,请您根据指引进行处理
- Antom 发送的通知结果由 Antom 加签,故建议您验证签名以确认通知由 Antom 发送。参考以下代码示例对支付通知进行验签:
/**
* 接收通知
*
* @param request 请求
* @param notifyBody 通知体
* @return Result
*/
@PostMapping("/receiveNotify")
@ResponseBody
public Result receiveNotify(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");
try {
// 验证通知签名
boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId,
requestTime, signature, notifyBody, ANTOM_PUBLIC_KEY);
if (!verifyResult) {
throw new RuntimeException("Invalid notify signature");
}
// 反序列化通知体
JSONObject jsonObject = JSON.parseObject(notifyBody);
String notifyType = (String)jsonObject.get("notifyType");
if("PAYMENT_RESULT".equals(notifyType)){
AlipayPayResultNotify paymentNotify = jsonObject.toJavaObject(AlipayPayResultNotify.class);
if (paymentNotify != null && "SUCCESS".equals(paymentNotify.getResult().getResultCode())) {
// 处理您的业务逻辑
// 例如:将支付信息与买家关系存入数据库
System.out.println("receive payment notify: " + JSON.toJSONString(paymentNotify));
return Result.builder().resultCode("SUCCESS").resultMessage("success.").resultStatus(ResultStatusType.S).build();
}
}
// 其他类型的通知
} catch (Exception e) {
// 处理错误情况
return Result.builder().resultCode("FAIL").resultMessage("fail.").resultStatus(ResultStatusType.F).build();
}
return Result.builder().resultCode("SYSTEM_ERROR").resultMessage("system error.").resultStatus(ResultStatusType.F).build();
}- 收到通知后,您无需对响应通知结果做加签处理,但是对于每个通知请求均需按以下固定格式响应,与订单支付成功与否无关。
{
"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": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a****"
}以下是响应报文的示例:
{
"actualPaymentAmount": {
"currency": "USD",
"value": "1"
},
"customsDeclarationAmount": {
"currency": "CNY",
"value": "7"
},
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"paymentId": "20250305194010800100188690281017336",
"paymentMethodType": "ALIPAY_CN",
"paymentRedirectUrl": "https://checkout.antom.com/checkout-page/pages/payment/index.html?sessionData=%2BCUim8L0KviXagaygm9xBL5jZ%2F75w6gAX1nn8pcuFuGkIsMoHtD6U88YSyMrMJvorbwnBg5uQv8e6pyvIpjDQQ%3D%3D%26%26SG%26%26188%26%26eyJleHRlbmRJbmZvIjoie1wiT1BFTl9NVUxUSV9QQVlNRU5UX0FCSUxJVFlcIjpcInRydWVcIixcImxvY2FsZVwiOlwiZW5fVVNcIixcImRpc3BsYXlBbnRvbUxvZ29cIjpcInRydWVcIn0iLCJwYXltZW50U2Vzc2lvbkNvbmZpZyI6eyJwYXltZW50TWV0aG9kQ2F0ZWdvcnlUeXBlIjoiQUxMIiwicHJvZHVjdFNjZW5lIjoiQ0hFQ0tPVVRfUEFZTUVOVCIsInByb2R1Y3RTY2VuZVZlcnNpb24iOiIxLjAifSwic2VjdXJpdHlDb25maWciOnsiYXBwSWQiOiIiLCJhcHBOYW1lIjoiT25lQWNjb3VudCIsImJpelRva2VuIjoiNlRjZGJyMnJGM3JQWXg0aGtWckhxYnZqIiwiZ2F0ZXdheSI6Imh0dHBzOi8vaW1ncy1zZWEuYWxpcGF5LmNvbS9tZ3cuaHRtIiwiaDVnYXRld2F5IjoiaHR0cHM6Ly9vcGVuLXNlYS1nbG9iYWwuYWxpcGF5LmNvbS9hcGkvb3Blbi9yaXNrX2NsaWVudCIsIndvcmtTcGFjZUlkIjoiIn0sInNraXBSZW5kZXJQYXltZW50TWV0aG9kIjpmYWxzZX0%3D",
"paymentRequestId": "PAYMENT_20250305220039086_AUTO",
"paymentResultCode": "SUCCESS",
"paymentResultMessage": "success.",
"paymentStatus": "SUCCESS",
"paymentTime": "2025-03-05T06:02:34-08:00",
"pspCustomerInfo": {
"pspName": "ALIPAY_CN"
},
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}常见问题
问:支付通知何时发送?
答:这取决于支付是否完成:如果支付成功完成,Antom 通常会在 3 到 5 秒内发送异步通知。
问:授权失败是否有异步通知发送?
答:只有授权成功才会有异步通知发送,授权失败不会返回异步通知
问:异步通知会被重新发送吗?
答:是的,对于以下情况,异步通知将在 24 小时内自动重新发送:
- 如果由于网络原因没有收到异步通知;
- 如果您收到 Antom 的异步通知,但您没有按照返回收到确认信息的示例代码格式进行响应。
通知可以重发最多 8 次,或者直到收到正确的响应以终止传递。发送间隔如下:0 分钟,2 分钟,10 分钟,10 分钟,1 小时,2 小时,6 小时,15 小时。
问:授权通知和支付结果通知是分开的,授权通知一定是比支付结果通先收到吗?
答:由于网络稳定性不可控,可能会出现授权通知比支付结果通知晚到的情况。
问:是否支持授权查询接口?
答:目前暂未支持该能力。
问:在响应异步通知时,我需要添加数字签名吗?
支付后集成
取消授权
取消交易
退款
账单
最佳实践
- 智能风控服务
- 处理回跳结果
- 商户侧主动关单
- 支付失败重试