Antom Checkout Page 是一款高效便捷的低代码集成支付页面产品,支持多种主流支付方式并覆盖全球多个地区,满足不同市场和场景的需求。通过简单的开发配置,您即可快速搭建一个界面专业、功能齐全的收银台页面,为买家提供流畅便捷的支付体验,同时显著提升支付接入效率,助力业务增长。
本方案通过接口实现集成,在订阅支付场景中,买家在完成商品加购后可直接跳转至 Antom Checkout Page 进行支付,无需额外页面配置。
以下为集成 Checkout Page 首次订阅和后续扣款的用户体验:
买家从商户页面跳转至 Antom Checkout Page 页面:
使用已存卡信息进行支付:
买家从商户页面跳转至 Antom Checkout Page 页面:
部分支付方式需要跳转到第三方支付页面:
使用已存卡信息进行支付:
由 Antom 服务端发起后续的周期扣款,商户服务端通过接收订阅续期扣费通知为用户续订订阅服务,无页面交互。
使用 Antom Checkout Page 全托管模式订阅支付的流程包括以下步骤:
- 买家进入订阅商品页面并发起支付。
- 创建支付会话请求。
您可以调用 createPaymentSession(单笔支付)接口获取支付会话。 - 处理 Antom Checkout Page URL
商户前端加载 Antom Checkout Page URL,买家在 Checkout Page 上选择支付方式,然后完成支付。支付完成后会跳转至 Checkout Page 的结果页,然后再回到商户结果页。您也可以在 Antom Dashboard 配置直接跳转至商户结果页。 - 获取授权支付结果。
通过以下两种方法之一获取授权支付结果:
注意:对于卡支付及部分 APM 支付方式(如 Apple Pay、Google Pay 和 Pay by Bank),这些支付方式采用的是授权-请款模式,以上步骤仅完成了授权部分,即买家使用银行卡完成支付,其资金处于冻结状态。为了将买家的冻结资金转至您的账户,您还需要集成请款步骤。请款成功的结果将作为您发货的依据。 - 请款并获取请款结果。
默认情况下,Antom 会自动为您处理资金请款。您也可以通过调用 capture(单笔支付)接口来手动进行请款。随后,通过以下两种方法之一获取请款结果: - 获取订阅通知。
订阅关系生效后,Antom 会为您发送首期订阅通知及订阅续期通知。
- Antom 服务端向发卡行或支付方式发起扣款。
- 获取授权支付结果。
通过以下两种方法之一获取授权支付结果:
注意:对于卡支付及部分 APM 支付方式(如 Google Pay、Apple Pay 和 Pay by Bank),这些支付方式采用的是授权-请款模式,以上步骤仅完成了授权部分,即买家使用银行卡完成支付,其资金处于冻结状态。为了将买家的冻结资金转至您的账户,您还需要集成请款步骤。请款成功的结果将作为您发货的依据。 - 请款并获取请款结果。
后续扣款中,Antom 会自动为您处理资金请款。随后,通过以下两种方法之一获取请款结果:
- 获取订阅通知。
扣款成功或失败后,Antom 会为您发送当期订阅扣款通知。
以下图片展示了 APM 支付首次订阅支付的流程图:- 买家进入订阅商品页面并发起支付。
- 创建支付会话请求。
您可以调用 createPaymentSession(单笔支付)接口获取支付会话。 - 处理 Antom Checkout Page URL
商户前端加载 Antom Checkout Page URL,买家在 Checkout Page 上选择支付方式,然后完成支付。支付完成后会跳转至 Checkout Page 的结果页,然后再回到商户结果页。您也可以在 Antom Dashboard 配置直接跳转至商户结果页。 - 获取支付结果。
通过以下两种方法之一获取支付结果:
- 获取订阅通知。
订阅关系生效后,Antom 会为您发送首期订阅通知及订阅续期通知。
以下图片展示了 APM 支付后续周期扣款的流程图:- Antom 服务端向支付方式发起扣款。
- 获取支付结果。
通过以下两种方法之一获取支付结果:
- 获取订阅通知。
扣款成功或失败后,Antom 会为您发送当期订阅扣款通知。
以下图片分别展示了不同支付方式的订阅生命周期:
下图展示了卡支付、Google Pay 和 Apple Pay 支付整个订阅生命周期,包括创建订阅、签约绑定支付方式、完成首次扣款,以及在必要时发起退款等环节,旨在保障订阅的正常生效与费用处理的安全透明: 下图展示了 APM 支付整个订阅生命周期,包括创建订阅、签约绑定支付方式、完成首次扣款,以及在必要时发起退款等环节,旨在保障订阅的正常生效与费用处理的安全透明: 在您开始集成前,请阅读集成指南及接口概述文档,了解服务端接口的集成步骤及调用接口的注意事项,并确保已完成以下预配置: - 已获得 client ID。
- 已完成密钥配置。
- 已完成异步通知接收地址的配置。
- 集成服务端 SDK 资源包,并完成接口库安装及请求示例初始化。具体操作请参阅服务端 SDK。
开始集成,请按照以下步骤操作:
- 创建支付会话
- 跳转至 Antom Checkout Page 页面
- 授权/支付结果通知
- (可选)请款并获取请款通知
- 获取订阅通知
创建支付会话请求包含以下关键参数:
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.CASHIER_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.CHECKOUT_PAYMENT);
// 设置订阅信息
SubscriptionInfo subscriptionInfo = new SubscriptionInfo();
subscriptionInfo.setSubscriptionDescription("TEST_SUBSCRIPTION");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
subscriptionInfo.setSubscriptionStartTime(ZonedDateTime.now().format(formatter));
subscriptionInfo.setSubscriptionEndTime(ZonedDateTime.now().plusYears(1).format(formatter));
subscriptionInfo.setSubscriptionNotifyUrl("https://your.example.com/subscriptionNotify");
// 设置订阅周期规则
PeriodRule periodRule = new PeriodRule();
periodRule.setPeriodType("YEAR");
periodRule.setPeriodCount(1);
subscriptionInfo.setPeriodRule(periodRule);
alipayPaymentSessionRequest.setSubscriptionInfo(subscriptionInfo);
// 设置金额
Amount amount = Amount.builder().currency("SGD").value("6000").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置买家信息
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// 设置订单信息
Order order = Order.builder().referenceOrderId(orderId)
.orderDescription("antom ckp testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// 设置支付方式
AvailablePaymentMethod availablePaymentMethod = new AvailablePaymentMethod();
HashMap<String, Object> methodData = new HashMap<>();
methodData.put("is3DSAuthentication", true);
List<PaymentMethodTypeItem> paymentMethodTypeList = new ArrayList<>();
PaymentMethodTypeItem paymentMethodTypeItem = new PaymentMethodTypeItem();
paymentMethodTypeItem.setPaymentMethodType("CARD");
availablePaymentMethod.setPaymentMethodTypeList(paymentMethodTypeList);
availablePaymentMethod.setPaymentMethodMetaData(methodData);
alipayPaymentSessionRequest.setAvailablePaymentMethod(availablePaymentMethod);
// 设置环境
Env env = Env.builder().terminalType(TerminalType.WEB).clientIp("1.2.3.4").build();
alipayPaymentSessionRequest.setEnv(env);
// 替换为您的通知地址
// 或者在此处配置您的通知地址: <a href="https://dashboard.antom.com/global-payments/developers/iNotify">通知 URL</a>
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com/payment/receiveNotify");
// 替换为您的跳转地址
alipayPaymentSessionRequest.setPaymentRedirectUrl(
"http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);
// 设置结算策略
// 替换为您现有的结算币种
SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// 替换为您的 clientId
alipayPaymentSessionRequest.setClientId(clientId);
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = defaultAlipayClient.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// 处理错误情况
}
}
以下为请求报文示例:
{
"env": {
"clientIp": "1.*.*.*",
"terminalType": "WEB"
},
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "SGD",
"value": "6000"
},
"orderDescription": "antom ckp testing order",
"referenceOrderId": "9aec4249-1934-4294-8c30-1993a157da5f"
},
"paymentAmount": {
"currency": "SGD",
"value": "6000"
},
"availablePaymentMethod": {
"paymentMethodMetaData": {
"is3DSAuthentication": true
},
"paymentMethodTypeList": []
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com/payment/receiveNotify",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com/payment/redirect",
"paymentRequestId": "601e5c9e-78b3-455e-84bb-ee41f88c6c07",
"productCode": "CASHIER_PAYMENT",
"productScene": "CHECKOUT_PAYMENT",
"settlementStrategy": {
"settlementCurrency": "USD"
},
"subscriptionInfo": {
"periodRule": {
"periodCount": 1,
"periodType": "YEAR"
},
"subscriptionDescription": "TEST_SUBSCRIPTION",
"subscriptionEndTime": "2027-03-12T10:38:54+08:00",
"subscriptionNotifyUrl": "https://your.example.com/subscription/notify",
"subscriptionStartTime": "2026-03-12T10:38:54+08:00"
}
}
以下代码展示了一个响应的示例,其中包含以下关键参数:
- paymentSessionData:将返回给前端的支付会话数据。
- paymentSessionExpiryTime:支付会话的过期时间。
- normalUrl:Checkout Page 页面的跳转链接。
{
"normalUrl": "https://checkout.antom.com/checkout-page/pages/payment/index.html?sessionData=cwnCzs7PcMfU03oKT1F%2BPHrpJmhr5k%2FF8nAcL4GP4PIin2bG4nFyF0NmqIOyf8Lt7Rh1%2BmgE27Csjx3Xhr8lkA%3D%3D%26%26SG%26%26188%26%26eyJlbGlnaWJsZUVhc3lQYXlNYXJrZXRpbmciOmZhbHNlLCJleHRlbmRJbmZvIjoie1wiT1BFTl9NVUxUSV9QQVlNRU5UX0FCSUxJVFlcIjpcInRydWVcIixcImRpc3BsYXlBbnRvbUxvZ29cIjpcInRydWVcIn0iLCJuZWVkQWNjb3VudENvbmZpcm1QYWdlIjpmYWxzZSwicGF5bWVudFNlc3Npb25Db25maWciOnsicGF5bWVudE1ldGhvZENhdGVnb3J5VHlwZSI6IkFMTCIsInByb2R1Y3RTY2VuZSI6IkNIRUNLT1VUX1BBWU1FTlQiLCJwcm9kdWN0U2NlbmVWZXJzaW9uIjoiMS4wIn0sInNlY3VyaXR5Q29uZmlnIjp7ImFwcElkIjoiIiwiYXBwTmFtZSI6Ik9uZUFjY291bnQiLCJiaXpUb2tlbiI6IjZUY2RicjJyRjNyUFl4NGhrVnJIcWJ2aiIsImdhdGV3YXkiOiJodHRwczovL2ltZ3Mtc2VhLmFsaXBheS5jb20vbWd3Lmh0bSIsImg1Z2F0ZXdheSI6Imh0dHBzOi8vb3Blbi1zZWEtZ2xvYmFsLmFsaXBheS5jb20vYXBpL29wZW4vcmlza19jbGllbnQiLCJ3b3JrU3BhY2VJZCI6IiJ9LCJza2lwUmVuZGVy******udE1ldGhvZCI6ZmFsc2V9&shadow=true",
"paymentSessionData": "4dChA3EBSSxaN9XOjRZ0zN3C8l8xUEAXQJRPDA5O+7TYW/kJ9tR76f**********vPiEEUII0uZciWVbjNIpxElA==&&SG&&188&&eyJlbGlnaWJsZUVhc3lQYXlNYXJrZXRpbmciOmZhbHNlLCJleHRlbmRJbmZvIjoie1wiT1BFTl9NVUxUSV9QQVlNRU5UX0FCSUxJVFlcIjpcInRydWVcIixcImRpc3BsYXlMYXlvdXRcIjpcIkxFRlRfT1JERVJfQU5EX1JJR0hUX1BBWU1FTlRcIixcInRoZW1lVHlwZVwiOlwiQ1VTVE9NSVpFXCIsXCJkaXNwbGF5QW50b21Mb2dvXCI6XCJmYWxzZVwifSIsIm5lZWRBY2NvdW50Q29uZmlybVBhZ2UiOmZhbHNlLCJwYXltZW50U2Vzc2lvbkNvbmZpZyI6eyJwYXltZW50TWV0aG9kQ2F0ZWdvcnlUeXBlIjoiQUxMIiwicHJvZHVjdFNjZW5lIjoiQ0hFQ0tPVVRfUEFZTUVOVCIsInByb2R1Y3RTY2VuZVZlcnNpb24iOiIxLjAifSwic2VjdXJpdHlDb25maWciOnsiYXBwSWQiOiIiLCJhcHBOYW1lIjoiT25lQWNjb3VudCIsImJpelRva2VuIjoiNlRjZGJyMnJGM3JQWXg0aGtWckhxYnZqIiwiZ2F0ZXdheSI6Imh0dHBzOi8vaW1ncy1zZWEuYWxpcGF5LmNvbS9tZ3cuaHRtIiwiaDVnYXRld2F5IjoiaHR0cHM6Ly9vcGVuLXNlYS1nbG9iYWwuYWxpcGF5LmNvbS9hcGkvb3Blbi9yaXNrX2NsaWVudCIsIndvcmtTcGFjZUlkIjoiIn0sInN********ZXJQYXltZW50TWV0aG9kIjpmYWxzZX0=",
"paymentSessionExpiryTime": "2026-03-12T11:38:59+08:00",
"paymentSessionId": "4dChA3EBSSxaN9XOjRZ0zN3C8l8x*********DA5O+7S4zYs/gYmYI0w5X1FgRTmT",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
下表展示了响应代码中 result.resultStatus 字段可能返回的值,请您根据指引进行处理:
注意:如果您未收到响应报文,可能是网络超时所致,请更换 paymentRequestId 重新调用接口以解决问题。
步骤 2:跳转至 Antom Checkout Page 页面(normalUrl)
客户端
商户服务端拿到 Antom 返回的 Checkout Page 页面地址(normalUrl )后,将该地址传递给前端,由商户前端跳转至 Antom Checkout Page 页面。
以下为商户前端加载 normalUrl 的示例代码:
if (serverResponse.normalUrl != null) {
window.open(serverResponse.normalUrl, '_blank');
}
window.location.href = URL;
下图展示了跳转的 Antom Checkout Page 页面效果:
首笔交易是买家参与的交易,需要进行身份验证,用于保障后续买家不在场的周期性扣费的安全。因此对于首笔交易的身份验证要求见下表:
常见问题
问:paymentRedirectUrl 在传参上有些什么注意点?
答:默认设置为 HTTPS 地址,同时 URL 中的特殊字符能进行编码处理,否则会支付异常。
问:支付结果页内容如何展示?
答:您需要通过在 createPaymentSession(单笔支付)接口中指定 paymentRedirectUrl 字段来提供一个 HTTPS 地址。该地址用于在商户端显示支付结果。在支付成功和支付失败的情况下,可能都有入口可以从支付方式端回跳到商户页面。因此,请勿将 paymentRedirectUrl 固定写成“订阅创建成功页面”,而是以服务端返回的结果为准,避免引起买家误解。
问:回跳商户结果页是否代表订阅创建成功?
答:不能仅凭回跳商户页面来判断订阅创建是否成功,具体有以下三种情况:
- 买家支付成功后,可能因网络等原因导致未能回跳至商户页。
- 即使买家未完成支付,也可能通过支付方式端的入口回跳至商户页面。
- 即使买家完成支付,也可能因为请款失败而导致订阅关系没有生效。
在支付处理流程中,Antom 会根据不同的支付方式类型向您发送相应的结果通知。
- 对于卡支付、Google Pay 和 Apple Pay 支付场景,Antom 发送的是授权结果通知,告知您授权是否成功。只有授权支付成功后才会触发请款,请依据请款结果作为发货依据。
- 对于 APM 支付场景,当支付成功或失败时 Antom 会发送的是支付结果通知。
- 设置接收通知的 webhook URL:Antom 允许您在 createPaymentSession(单笔支付)接口的 paymentNotifyUrl 参数中指定链接。如果每个支付的地址相同,也可以在 Antom Dashboard 中配置该地址。
以下为异步通知请求体的代码示例:
{
"actualPaymentAmount": {
"currency": "USD",
"value": "1"
},
"cardInfo": {
"avsResultRaw": "U",
"cardBrand": "VISA",
"cardCategory": "CONSUMER",
"cardNo": "************0550",
"credentialTypeUsed": "PAN",
"cvvResultRaw": "M",
"funding": "PREPAID",
"issuingCountry": "MY",
"networkTransactionId": "20251009031****b937936376",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "mockCavv",
"challengeCancel": "",
"challenged": true,
"dsTransactionId": "cce18b6e-b55e-40ff-814c-619b4598****",
"eci": "02",
"threeDSOffered": true,
"threeDSVersion": "2.1.0",
"threeDStransactionStatusReason": ""
}
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"paymentCreateTime": "2025-10-08T19:11:20-07:00",
"paymentId": "202510091940108****01889B0255128143",
"paymentMethodType": "GOOGLEPAY",
"paymentRequestId": "PAYMENT_202510****1050687_AUTO",
"paymentResultInfo": {
"avsResultRaw": "U",
"cardBrand": "VISA",
"cardCategory": "CONSUMER",
"cardNo": "************0550",
"credentialTypeUsed": "PAN",
"cvvResultRaw": "M",
"funding": "PREPAID",
"issuingCountry": "MY",
"networkTransactionId": "2025100903****9b937936376",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "mockCavv",
"challengeCancel": "",
"challenged": true,
"dsTransactionId": "cce18b6e-b55e-40ff-814c-619b4598****",
"eci": "02",
"threeDSOffered": true,
"threeDSVersion": "2.1.0",
"threeDStransactionStatusReason": ""
}
},
"paymentTime": "2025-10-08T19:11:38-07:00",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
- 异步通知验签。
当您收到 Antom 的异步通知,您需要按照返回收到确认信息的格式返回响应,但无需做加签处理。 您需要按照以下方法对 Antom 发送的通知进行验签:
/**
* 接收支付通知
*
* @param request request
* @param notifyBody notify body
* @return Result
*/
@PostMapping("/receivePaymentNotify")
@ResponseBody
public Result receivePaymentNotify(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");
}
// 反序列化通知报文体
AlipaySubscriptionPayNotify paymentNotify = JSON.parseObject(notifyBody, AlipaySubscriptionPayNotify.class);
if (paymentNotify != null && "SUCCESS".equals(paymentNotify.getResult().getResultCode())) {
// 处理你的业务逻辑
// 例如:通过 subscriptionRequestId 与用户 ID 的关系保存用户的支付信息。
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();
}
- 响应通知结果。无论订单是否支付成功,每个通知请求均需按以下固定格式响应。否则,Antom 会重新发送异步通知。
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
}
}
- 设置接收通知的 webhook URL:Antom 允许您在 createPaymentSession(单笔支付)接口的 paymentNotifyUrl 参数中指定链接。如果每个支付的地址相同,也可以在 Antom Dashboard 中配置该地址。
以下为异步通知请求体的代码示例:
{
"actualPaymentAmount": {
"currency": "MYR",
"value": "498"
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "MYR",
"value": "498"
},
"paymentCreateTime": "2025-11-04T02:07:37-08:00",
"paymentId": "20251104194010800****88330226108041",
"paymentRequestId": "eshop_2108220418892243_5110404369713****",
"paymentResultInfo": {},
"paymentTime": "2025-11-04T02:07:51-08:00",
"pspCustomerInfo": {
"pspCustomerId": "100000****134758",
"pspName": "TNG"
},
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
- 异步通知验签。
当您收到 Antom 的异步通知,您需要按照返回收到确认信息的格式返回响应,但无需做加签处理。 您需要按照以下方法对 Antom 发送的通知进行验签:
/**
* 接收支付通知
*
* @param request request
* @param notifyBody notify body
* @return Result
*/
@PostMapping("/receivePaymentNotify")
@ResponseBody
public Result receivePaymentNotify(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");
}
// 反序列化通知报文体
AlipaySubscriptionPayNotify paymentNotify = JSON.parseObject(notifyBody, AlipaySubscriptionPayNotify.class);
if (paymentNotify != null && "SUCCESS".equals(paymentNotify.getResult().getResultCode())) {
// 处理你的业务逻辑
// 例如:通过 subscriptionRequestId 与用户 ID 的关系保存用户的支付信息。
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();
}
- 响应通知结果。无论订单是否支付成功,每个通知请求均需按以下固定格式响应。否则,Antom 会重新发送异步通知。
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
}
}
授权支付成功后,Antom 默认自动为您请款,也支持您手动发起请款。同时,Antom 会使用 notifyCapture(单笔支付)将请款结果通知发送给您,您也可以通过主动查询来获取请款结果。您需要根据请款结果来决定是否发货,具体操作请参阅请款。 订阅关系生效后,Antom 会为您发送以下通知:
Antom 将通过 HTTPS 向您在接口或 Antom Dashboard 中配置的 Webhook 推送以下事件通知:
请按以下步骤获取订阅状态通知:
- 设置接收通知的 webhook URL:通过 createPaymentSession(单笔支付)接口的 subscriptionInfo.subscriptionNotifyUrl 参数设置。以下是两种订阅状态的通知示例:
- 当 subscriptionNotificationType 的值为
CREATE
时,请根据 subscriptionStatus 的值判断订阅关系:
ACTIVE
:表示订阅关系生效。TERMINATED
:表示订阅关系失效。
{
"periodRule": {
"periodCount": 1,
"periodType": "MONTH"
},
"subscriptionEndTime": "2074-02-20T01:16:17-08:00",
"subscriptionId": "20240914*********00000000050000010226",
"subscriptionNotificationType": "CREATE",
"subscriptionRequestId": "SUBSCRIPTION_2024440914*****o009851_AUTO",
"subscriptionStartTime": "2024-09-13T19:30:17-07:00",
"subscriptionStatus": "ACTIVE"
}
- 当 subscriptionNotificationType 的值为
TERMINATE
时,订阅关系失效。
{
"periodRule": {
"periodCount": 1,
"periodType": "WEEK"
},
"subscriptionId": "2025102619******00000160000671943",
"subscriptionLastUpdateTime": "2025-10-26T09:51:13-07:00",
"subscriptionNotificationType": "TERMINATE",
"subscriptionRequestId": "PR_en_****176",
"subscriptionStartTime": "2025-10-26T10:01:13-07:00",
"subscriptionStatus": "TERMINATED"
}
- 异步通知验签。
当您收到 Antom 的异步通知,您需要按照返回收到确认信息的格式返回响应,但无需做加签处理。 您需要按照以下方法对 Antom 发送的通知进行验签:
/**
* 接收订阅通知
*
* @param request request
* @param notifyBody notify body
* @return Result
*/
@PostMapping("/receiveSubscriptionNotify")
@ResponseBody
public Result receiveSubscriptionNotify(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");
}
// 反序列化通知报文体
AlipaySubscriptionNotify subscriptionNotify = JSON.parseObject(notifyBody, AlipaySubscriptionNotify.class);
if (subscriptionNotify != null && SubscriptionNotificationType.CREATE.equals(subscriptionNotify.getSubscriptionNotificationType())) {
// 处理你的业务逻辑
// 例如:通过 subscriptionRequestId 与用户 ID 的关系保存用户的订阅信息。
System.out.println("receive subscription notify: " + JSON.toJSONString(subscriptionNotify));
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();
}
- 响应通知结果。无论订单是否支付成功,每个通知请求均需按以下固定格式响应。否则,Antom 会重新发送异步通知。
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
}
}
请按以下步骤获取当期扣款结果通知:
- 设置接收通知的 webhook URL:在 createPaymentSession(单笔支付)接口请求的 paymentNotifyUrl 参数设置和 Antom Dashboard 配置。
以下为异步通知请求体的代码示例:
{
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"notifyType": "PAYMENT_RESULT",
"paymentCreateTime": "2025-10-08T19:10:51-07:00",
"paymentId": "20251009194010800*****89B0255128143",
"paymentTime": "2025-10-08T19:11:40-07:00",
"periodEndTime": "2025-08-02T19:15:29-07:00",
"periodStartTime": "2025-07-26T19:15:29-07:00",
"phaseNo": "1",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success",
"resultStatus": "S"
},
"subscriptionId": "202510091*****00000000E0000032897",
"subscriptionRequestId": "PAYMENT_2025****1050687_AUTO"
}
关键参数说明:
- notifyType:通知类型,值为
PAYMENT_RESULT
。 - phaseNo:订阅当期的期数。
- periodStartTime:本期订阅开始时间。
- periodEndTime:本期订阅结束时间。
- paymentAmount:每期周期扣款的金额。
- 异步通知验签。
当您收到 Antom 的异步通知,您需要按照返回收到确认信息的格式返回响应,但无需做加签处理。 您需要按照以下方法对 Antom 发送的通知进行验签:
/**
* 接收支付通知
*
* @param request HTTP 请求对象
* @param notifyBody 通知的请求体
* @return Result 返回结果
*/
@PostMapping("/receivePaymentNotify")
@ResponseBody
public Result receivePaymentNotify(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("通知签名无效");
}
// 反序列化通知报文体
AlipaySubscriptionPayNotify paymentNotify = JSON.parseObject(notifyBody, AlipaySubscriptionPayNotify.class);
if (paymentNotify != null && "SUCCESS".equals(paymentNotify.getResult().getResultCode())) {
// 处理你的业务逻辑
// 例如:通过 subscriptionRequestId 与用户 ID 的关系保存用户的支付信息。
System.out.println("接收到支付通知: " + 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();
}
- 响应通知结果。无论订单是否支付成功,每个通知请求均需按以下固定格式响应。否则,Antom 会重新发送异步通知。
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
}
}
常见问题
问:Antom 会重新发送异步通知吗?
答:会。对于以下情况,异步通知将在 24 小时内自动重新发送:
- 由于网络原因未收到异步通知。
- 如果收到来自 Antom 的异步通知,但您没有按照返回收到确认信息的格式进行响应。
通知可以重发最多 8 次,或者直到收到正确的响应以终止传递。发送间隔如下:0 分钟,2 分钟,10 分钟,10 分钟,1 小时,2 小时,6 小时和 15 小时。
问:收到支付结果通知是否需要验签?
答:需要。通过验签 Antom 会发送保障回调请求给您,验签时请注意拼装待验签报文时需按标准处理:<http-method> <http-uri> <client-id>.<request-time>.<request-body>
,特别是针对 <request-body>
需直接取值而非解析 JSON 后拼装。
问:若首次支付失败,订阅关系会生效吗?
答:当订阅开通的首次扣款失败时,订阅关系将不会生效,Antom 系统会通过 Webhook 推送 subscriptionStatus 为TERMINATED
的状态通知给您,表明订阅开通失败。
问:订阅超时时间是多久?
答:
您还可以通过 subscriptionExpiryTime 字段来指定过期时间。
当订阅创建成功并建立有效关系后,Antom 系统将会根据您配置的订阅规则,自动发起续订扣款,并通过 Webhook 推送相应的支付结果通知,实现周期性扣费。触发续订扣款的时间和规则如下:
- 触发时间:续订扣款将在下一个订阅周期起始日的前 24 小时自动触发。您可以依据上一周期支付结果通知中的 periodEndTime 字段,向前推 24 小时以判断下一周期扣款的发起时间。
- 周期规则:续费周期及扣款频率将按照订阅时设定的 periodRule 执行,例如按日、按月、按季度或按年扣款。
以下为各场景异步通知的示例代码:
以下为授权支付结果通知请求体的示例代码:
{
"actualPaymentAmount": {
"currency": "USD",
"value": "1"
},
"cardInfo": {
"avsResultRaw": "U",
"cardBrand": "VISA",
"cardCategory": "CONSUMER",
"cardNo": "************0550",
"credentialTypeUsed": "PAN",
"cvvResultRaw": "M",
"funding": "PREPAID",
"issuingCountry": "MY",
"networkTransactionId": "20251009031****b937936376",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "mockCavv",
"challengeCancel": "",
"challenged": true,
"dsTransactionId": "cce18b6e-b55e-40ff-814c-619b4598****",
"eci": "02",
"threeDSOffered": true,
"threeDSVersion": "2.1.0",
"threeDStransactionStatusReason": ""
}
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"paymentCreateTime": "2025-10-08T19:11:20-07:00",
"paymentId": "2025100919401080****1889B0255128143",
"paymentMethodType": "GOOGLEPAY",
"paymentRequestId": "PAYMENT_2025100****050687_AUTO",
"paymentResultInfo": {
"avsResultRaw": "U",
"cardBrand": "VISA",
"cardCategory": "CONSUMER",
"cardNo": "************0550",
"credentialTypeUsed": "PAN",
"cvvResultRaw": "M",
"funding": "PREPAID",
"issuingCountry": "MY",
"networkTransactionId": "20251009031****b937936376",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "mockCavv",
"challengeCancel": "",
"challenged": true,
"dsTransactionId": "cce18b6e-b55e-40ff-814c-619b4598****",
"eci": "02",
"threeDSOffered": true,
"threeDSVersion": "2.1.0",
"threeDStransactionStatusReason": ""
}
},
"paymentTime": "2025-10-08T19:11:38-07:00",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
以下为请款通知请求体的示例代码:
{
"captureAmount": {
"currency": "USD",
"value": "1"
},
"captureId": "202510091940108070001889B0280060023",
"captureRequestId": "PAYMENT_20251009101050687_AUTO",
"captureTime": "2025-10-08T19:11:40-07:00",
"notifyType": "CAPTURE_RESULT",
"paymentId": "202510091940108001001889B0255128143",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
以下为当期扣款结果通知请求体的示例代码:
{
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"notifyType": "PAYMENT_RESULT",
"paymentCreateTime": "2025-10-08T19:10:51-07:00",
"paymentId": "202510091940108001001889B0255128143",
"paymentTime": "2025-10-08T19:11:40-07:00",
"periodEndTime": "2025-08-02T19:15:29-07:00",
"periodStartTime": "2025-07-26T19:15:29-07:00",
"phaseNo": "1",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success",
"resultStatus": "S"
},
"subscriptionId": "202510091900000000000000E0000032897",
"subscriptionRequestId": "PAYMENT_20251009101050687_AUTO"
}
关键参数说明:
- notifyType:通知类型,值为
PAYMENT_RESULT
。 - phaseNo:订阅当期的期数。
- periodStartTime:本期订阅开始时间。
- periodEndTime:本期订阅结束时间。
- paymentAmount:每期周期扣款的金额。
APM 支付场景下,异步通知通常分为以下场景:
以下为各场景异步通知的示例代码:
以下为当期扣款结果通知请求体的示例代码:
{
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"notifyType": "PAYMENT_RESULT",
"paymentCreateTime": "2025-10-08T19:10:51-07:00",
"paymentId": "202510091940108001001889B0255128143",
"paymentTime": "2025-10-08T19:11:40-07:00",
"periodEndTime": "2025-08-02T19:15:29-07:00",
"periodStartTime": "2025-07-26T19:15:29-07:00",
"phaseNo": "1",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success",
"resultStatus": "S"
},
"subscriptionId": "202510091900000000000000E0000032897",
"subscriptionRequestId": "PAYMENT_20251009101050687_AUTO"
}
关键参数说明:
- notifyType:通知类型,值为
PAYMENT_RESULT
。 - phaseNo:订阅当期的期数。
- periodStartTime:本期订阅开始时间。
- periodEndTime:本期订阅结束时间。
- paymentAmount:每期周期扣款的金额。
常见问题
问:若扣款失败会导致订阅关系失效吗?
答:创建订阅的首期扣款如果失败,订阅关系将不会生效;若订阅关系已生效但后续的周期扣款失败(如余额不足),订阅状态仍保持有效;若未主动取消订阅,Antom 将会在下一期继续周期扣款。
问:扣款失败会发送当期扣款通知吗,会重试吗?
答:扣款失败会发送扣款失败通知。卡支付、Google Pay 和 Apple Pay 的订阅支付场景下,Antom 不会发起重试;APM 的订阅支付场景下,Antom 会发起多次重试。商户侧如需自行发起重试,可联系技术支持确定方案。
问:假如首期扣款是 2 月 28 日、3 月 31 日或 4 月 30 日这些月末时间点,那下一期的扣费时间怎么定义?
答:订阅的周期逻辑为按选定的日期来发起下一次扣款,如果下一个周期没有这个日期,则往前推到最后一天,例如:
- 首期 1.28,二期 2.28,三期 3.28,四期 4.28。
- 首期 1.31,二期 2.28,三期 3.31,四期 4.30。
- 首期 1.30,二期 2.28,三期 3.30,四期 4.30。
问:后续的周期扣款如何跟首期合约关联?
答:针对周期扣款通知,可以根据通知请求中的 subscriptionRequestId 或 subscriptionId 与首期合约关联。针对卡支付、Google Pay 和 Apple Pay 的周期扣款,Antom 还会额外发送授权结果通知和请款结果通知,这两个通知可以根据 paymentId 关联到周期扣款通知中的 paymentId 并最终关联上首期合约的 subscriptionId。 完成订阅支付后,您可以对交易进行以下操作:
订阅确认后,您可以查询以下订阅信息:
除了可以通过异步通知的功能获取买家的支付结果,同时也支持您通过主动查询服务来获取对应的结果。您可以调用 inquiryPayment 接口,可使用支付会话中的 paymentRequestId 查询支付状态。 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();
// 处理错误情况
}
}
以下代码展示了一个响应报文的示例:
{
"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=your_SESSION_DATA",
"paymentRequestId": "PAYMENT_202503****0039086_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"
}
}
下表展示了响应报文中 paymentStatus 字段可能的值:
注意:在查询交易时,如果买家没有提交订单,就会一致报错 ORDER_NOT_EXIST
,提交订单以后才不会报错。 Antom 提供订阅试用功能,帮助买家在正式购买订阅计划前,以免费或优惠价格在限定时间内体验产品或服务。详情请参阅订阅试用文档。 终止订阅功能允许买家在不需要继续使用相关服务时,随时取消当前订阅。详情请参阅终止订阅文档。 对于支付成功后的订单,如买家在当天内申请取消订单或退款,您可以通过 Antom 提供的取消交易能力将订单状态取消或解冻。此外,对于尚未完成支付的订单,您也可以直接进行取消,具体的集成方案见取消交易文档。 对于已支付成功的订单,如您需向买家发起退款,Antom 提供以下两种方式。
Antom 的退款能力如下:
- 支持全额退款。
- 支持部分多次退款,多次退款的总金额需小于等于请款金额。
若买家选择使用卡支付方式,会涉及到争议相关的集成,详情请参见争议文档。 交易完成后,使用 Antom 提供的财务报告进行对账。有关如何对账和 Antom 结算规则的更多信息,请参阅对账。 注意:如果您通过接口传入参数来指定支付方式,则优先取接口传值。
此功能为您带来以下优势: