集成快捷支付(SDK)
快捷支付(EasySafePay)是一款专注于小额高频支付场景的极简支付解决方案,通过创新的“首次支付即绑卡”和一键支付功能,大幅简化支付流程,买家首次交易即可完成钱包绑定或直接支付,后续支付无需重复验证即可极速完成。
该方案依托行业领先的智能风控系统、动态轮询技术和支付失败挽回策略,在确保交易安全的同时将支付成功率提升至行业顶尖水平,实现了买家支付体验、商户转化率和平台生态价值的三方共赢。
Web/WAP
iOS
Android
WebView
用户体验
通过简单的浏览器集成,可快速接入电子钱包和网银转账支付功能。



各支付方式在浏览器端的用户体验存在差异,具体交互体验详见下表:
电子钱包
网银转账
电子钱包
电子钱包支付场景下,买家确认支付后,系统将引导买家在商户页面或支付方式应用程序内完成交易。首次支付验证与后续支付简化流程如图所示:
首次支付
后续支付
首次支付需完成安全验证,授权后即可享受免密支付。

后续支付仅需提交订单即可完成免密支付。

网银转账
网银转账支付场景下的体验流程如图所示,包含首次支付验证与后续支付简化流程。
首次支付
后续支付
首次支付需完成安全验证,授权后即可享受免密支付。

后续支付仅需提交订单即可完成免密支付。

支付流程
首次支付
后续支付
首次支付流程示意图:

- 买家进入商户收银台页面
- 创建支付会话请求
买家确认支付后,调用 createPaymentSession(快捷支付) 接口获取支付会话。 - 调用客户端 SDK
使用支付会话调用 SDK,SDK 将根据支付方式特性自动采集支付要素、渲染支付界面、处理页面跳转并引导买家完成支付。不同支付方式的交互差异详见用户体验。 - 获取授权结果
当授权成功时,Antom 会通过 notifyAuthorization 接口向您发送异步通知。
- 获取支付结果
可通过以下方式同步支付状态:
- 异步通知:在 createPaymentSession(快捷支付) 接口中指定 paymentNotifyUrl 来设置接收异步通知的地址。当支付成功或过期时,Antom 会使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口获取实时状态。
后续支付流程示意图:

- 买家进入商户收银台页面
- 创建支付会话请求
买家确认支付后,调用 createPaymentSession(快捷支付) 接口获取支付会话。 - 调用客户端 SDK
使用支付会话调用 SDK,SDK 将根据支付方式特性自动采集支付要素、渲染支付界面、处理页面跳转并引导买家完成支付。不同支付方式的交互差异详见用户体验。 - 获取支付结果
可通过以下方式同步支付状态:
- 异步通知:在 createPaymentSession(快捷支付) 接口中指定 paymentNotifyUrl 来设置接收异步通知的地址。当支付成功或过期时,Antom 会使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口获取实时状态。
集成准备
- 已获得 client ID。
- 已完成密钥配置。
- 已完成异步通知接收地址的配置。
- 集成 Antom 服务端 SDK 资源包,并完成接口库安装及请求示例初始化。具体操作请参阅服务端 SDK。
- 如需使用沙箱环境与生产环境进行联调测试,请提前两个工作日联系 Antom 技术支持申请配置。沙箱环境和生产环境需单独配置。
集成步骤
请按以下流程开始您的集成:
- (可选)预加载
- 创建支付会话
- 调用 SDK
- 获取授权和支付结果
(可选)步骤 1:预加载 SDK 客户端
在加载收银台列表页面时,执行预加载可显著提升收银台页面的渲染性能且无负面性能影响。建议在买家选择支付方式时触发预加载。
请参考以下代码实现预加载:
预加载 SDK
AMSEasyPay.preload();
步骤 2:创建支付会话 服务端
当买家选择由 Antom 提供的支付方式进行支付时,您需要收集支付请求 ID、订单金额、支付方式、订单描述、支付重定向页面链接和支付结果通知链接等必要信息。
各支付方式买家支付账户传参格式如下:
首次支付时传入买家支付账号可自动回填买家账号至支付页面,避免手动输入操作。以下是传入和未传入的体验对比图:
传入买家支付账号
未传入买家支付账号
无需输入登录账号。

需手动输入登录账号。

以下是首次支付和后续支付两种不同场景集成代码示例:
首次支付
后续支付
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// 转换金额单位(实际使用中,金额应在服务端计算)
// 详情请参考:<a href="https://docs.antom.com/ac/ref/cc">金额对象使用规则</a>
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();
// 设置金额
Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// 设置结算策略
// 替换为您现有的结算货币
SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
User loginUser = users.get(payment.getUserId());
// 设置买家信息
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// 设置 paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
// 买家已授权
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
paymentMethod.setPaymentMethodId(accessToken);
} else {
// 设置 agreementInfo
// 替换为您的 authState
String authState = UUID.randomUUID().toString();
AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).build();
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);
// 保存与 authState 对应的 paymentMethodType
authStatePayment.put(authState, payment);
// 买家在支付方式客户端注册时使用的登录 ID,登录 ID 可以是买家的电子邮箱地址或手机号码
// 指定此参数可免去买家手动输入登录 ID
if(StringUtil.isNotBlank(loginUser.getPhoneNumber()){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
if(StringUtil.isNotBlank(loginUser.getEmail() && "ALIPAY_HK".equals(payment.getPaymentMethodType())){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
}
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置订单信息
Order order = Order.builder().referenceOrderId(orderId)
.orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// 替换为您的通知 URL
// 或在此配置您的通知 URL:<a href="https://dashboard.antom.com/global-payments/developers/iNotify">通知URL</a>
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com/payment/receivePaymentNotify");
// 替换为您的重定向 URL
alipayPaymentSessionRequest.setPaymentRedirectUrl(
"http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
System.out.println("payment 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(), alipayPaymentSessionResponse));
}请求报文示例:
{
"agreementInfo": {
"authState": "authState001"
},
"order": {
"buyer": {
"referenceBuyerId": "referenceBuyerId001",
"buyerPhoneNo": "852-12****78"
},
"orderAmount": {
"currency": "HKD",
"value": "100"
},
"orderDescription": "orderDescription001",
"referenceOrderId": "referenceOrderId001"
},
"paymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
"paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
"paymentRequestId": "paymentRequestId001",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}响应报文示例:
{
"paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
"paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
"paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}请根据返回的 result.resultStatus 字段值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请更换 paymentRequestId 和 authstate 后重试接口调用。
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// 设置金额
// 需进行金额单位转换(实际金额应在服务端计算)
Amount amount = Amount.builder().currency("HKD").value("98080").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// 设置结算币种
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("USD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// 设置支付方式
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK")
.paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****").build();
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// 设置买家信息
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置订单信息
Order order = Order.builder().referenceOrderId(orderId).
orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// 替换为您的通知地址
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");
// 替换为您的跳转地址
alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// 处理异常情况
}
}
请求报文示例:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "HKD",
"value": "98080"
},
"orderDescription": "antom api testing order",
"referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311a090d"
},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentMethod": {
"paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com",
"paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2dd2b3",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}响应报文示例:
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}请根据返回的 result.resultStatus 字段值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请更换 paymentRequestId 后重试接口调用。
常见问题
问:请求参数的值可以使用中文字符吗?
答:为了避免某些支付方式的不兼容,不要在请求的字段中使用中文字符。
问:如何设置接收支付通知的链接?
答:在 createPaymentSession(快捷支付) 接口中指定参数 paymentNotifyUrl,以接收支付结果的异步通知(notifyPayment),或者在 Antom Dashboard 中配置接收链接。如果请求和 Antom Dashboard 中都指定了链接,请求中指定的值优先。
问:paymentAmount 和 orderAmount 的区别是什么?
答:paymentAmount 是指支付金额,orderAmount 是指订单金额。实际支付金额以 paymentAmount 为准。
问:支付请求中 paymentSessionExpiryTime 超时时间具体指的是什么时间?
答:paymentSessionExpiryTime 表示支付会话创建成功至买家完成支付提交的有效期。买家提交支付后,支付处理超时时间为 10 分钟。因此,买家从会话创建到支付完成的整体时限最长可达 1 小时 10 分钟。
问:在响应报文中有哪些重点关注字段?
答:关注响应报文中的以下字段:
- result.resultStatus:用于判断支付创建会话调用结果。
- paymentSessionData:加密的支付会话数据。将数据传递给前端用于调用 Antom SDK。
- paymentSessionExpiryTime:支付会话过期时间。
步骤 3:调用 SDK 客户端
在商户服务端获取到 paymentSessionData 后,可通过商户客户端调用 SDK,将收银台跳转至支付方式签约授权页。买家提交支付请求后,SDK 将自动处理加密通信、风控校验、页面跳转及支付指令执行,实现端到端的支付授权闭环流程。
1. 实例化 SDK
- 使用 AMSEasyPay来创建 SDK 实例。配置对象包括以下参数:
以下示例代码展示了如何通过 npm 或 CDN 实例化 SDK:
npm
CDN
npm 实例化 SDK
import { AMSEasyPay } from '@alipay/ams-checkout' //包管理
const checkoutApp = new AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({code, message})=>{},
});
CDN 实例化 SDK
const checkoutApp = new window.AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({code, message})=>{},
});
- 使用实例对象中的 createComponent创建一个支付组件,涉及的参数如下:
创建支付组件示例:
async function create(sessionData) {
await checkoutApp.createComponent({
sessionData: sessionData,
notRedirectAfterComplete: false // 默认设为 false,表示支付完成后将重定向至您的页面
});
}下图展示 SDK 将收银台跳转至支付方式签约授权页的渲染效果:

Web
WAP
从商户收银台页面跳转至支付方式页面

商户收银台页面拉起半浮层或者跳转到钱包应用程序

2. 处理 SDK 回调事件码
以下是
onEventCallback
返回的事件码及其处理建议:以下示例代码展示了如何处理回调函数:
function onEventCallback({ code }) {
switch (code) {
case 'SDK_PAYMENT_CANCEL':
console.log(
'买家取消了支付(买家未提交订单就退出了支付页面)。您可以在有效期内使用 paymentSessionData 重新调用 SDK;如果已过期,则需要发起新的 createPaymentSession (EasySafePay) 请求。'
);
break;
case 'SDK_CALL_URL_SUCCESS':
console.log('成功调起支付方式应用或跳转至商户页面。');
break;
case 'SDK_LAUNCH_PAYMENT_APP_ERROR':
console.log('跳转至支付方式的收银台页面失败,或跳转至商户页面失败。请检查调用 createPaymentSession (EasySafePay) 请求时 paymentRedirectUrl 参数是否正确传递。Web/WAP 场景很少出现跳转异常,但如遇任何异常,建议验证跳转链接。');
break;
case 'SDK_PAYMENT_SUCCESSFUL':
console.log('钱包已成功处理支付。请从 Antom 服务器获取最终支付结果,可通过 inquiryPayment API 或 notifyPayment API 确认结果。建议将买家重定向至支付结果页面。');
break;
case 'SDK_PAYMENT_FAIL':
console.log('钱包处理支付失败。请从 Antom 服务器获取最终支付结果,可通过 inquiryPayment API 或 notifyPayment API 确认结果。建议将买家重定向至支付结果页面。');
break;
default:
console.log(code);
}
};3. 销毁组件
请在以下场景调用
unmount
方法释放 SDK 组件资源:- 当买家切换视图离开收银台页面时,释放 createPaymentSession(快捷支付) 中创建的组件资源。
- 当买家发起多次支付时,释放之前 createPaymentSession(快捷支付) 中创建的组件资源。
- 在获取最终支付结果后释放组件资源。
// 释放 SDK 组件资源
checkoutApp.unmount();常见问题
问:一个 AMSEasypay 实例是否可以多次执行 createComponent?
答:不支持,若您要再次发起支付,请创建新的 AMSEasypay 实例。
问:首次支付和后续支付都需要调用 SDK 吗?
答:是的。
用户体验
本 iOS 集成指南旨在帮助您快速实现 App 内电子钱包与网银支付功能的集成,并轻松完成支付界面渲染。




各支付方式在 iOS 端的用户体验存在差异,具体交互体验详见下表:
电子钱包
网银转账
电子钱包
以下是电子钱包类支付方式首次支付和后续支付体验图:
首次支付
后续支付
首次支付时,买家可选择立即支付或完成授权流程。成功授权后,后续支付将启用免密功能。
在商户页面完成支付
跳转至支付方式应用程序支付


后续支付仅需提交订单即可完成免密支付。

网银转账
网银转账支付场景下的体验流程如图所示,包含首次支付验证与后续支付简化流程。
首次支付
后续支付
首次支付时,买家可选择立即支付或完成授权流程。成功授权后,后续支付将启用免密功能。

后续支付仅需提交订单即可完成免密支付。

支付流程
首次支付
后续支付
首次支付流程示意图:

- 买家进入商户收银台页面
- 创建支付会话请求
买家确认支付后,调用 createPaymentSession(快捷支付) 接口获取支付会话。 - 调用客户端 SDK
使用支付会话调用 SDK,SDK 将根据支付方式特性自动采集支付要素、渲染支付界面、处理页面跳转并引导买家完成支付。不同支付方式的交互差异详见用户体验。 - 获取授权结果
当授权成功时,Antom 会通过 notifyAuthorization 接口向您发送异步通知。
- 获取支付结果
可通过以下方式同步支付状态:
- 异步通知:在 createPaymentSession(快捷支付) 接口中指定 paymentNotifyUrl 来设置接收异步通知的地址。当支付成功或过期时,Antom 会使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口获取实时状态。
后续支付流程示意图:

- 买家进入商户收银台页面
- 创建支付会话请求
买家确认支付后,调用 createPaymentSession(快捷支付) 接口获取支付会话。 - 调用客户端 SDK
使用支付会话调用 SDK,SDK 将根据支付方式特性自动采集支付要素、渲染支付界面、处理页面跳转并引导买家完成支付。不同支付方式的交互差异详见用户体验。 - 获取支付结果
可通过以下方式同步支付状态:
- 异步通知:在 createPaymentSession(快捷支付) 接口中指定 paymentNotifyUrl 来设置接收异步通知的地址。当支付成功或过期时,Antom 会使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口获取实时状态。
集成准备
- 已获得 client ID。
- 已完成密钥配置。
- 已完成异步通知接收地址的配置。
- 集成 Antom 服务端 SDK 资源包,并完成接口库安装及请求示例初始化。具体操作请参阅服务端 SDK。
- 如需使用沙箱环境与生产环境进行联调测试,请提前两个工作日联系 Antom 技术支持申请配置。沙箱环境和生产环境需单独配置。
集成步骤
请按以下流程开始您的集成:
- (可选)预加载
- 创建支付会话
- 调用 SDK
- 获取授权和支付结果
(可选)步骤 1:预加载 SDK 客户端
在加载收银台列表页面时,执行预加载可显著提升收银台页面的渲染性能且无负面性能影响。建议在买家选择支付方式时触发预加载。
请参考以下代码实现预加载:
预加载 SDK
[AMSEasyPay.shared preload];步骤 2:创建支付会话 服务端
当买家选择由 Antom 提供的支付方式进行支付时,您需要收集支付请求 ID、订单金额、支付方式、订单描述、支付重定向页面链接和支付结果通知链接等必要信息。
各支付方式买家支付账户传参格式如下:
首次支付时传入买家支付账号可自动回填买家账号至支付页面,避免手动输入操作。以下是传入和未传入的体验对比图:
传入买家支付账号
未传入买家支付账号
无需输入登录账号。

需手动输入登录账号。

以下是首次支付和后续支付两种不同场景集成示例:
首次支付
后续支付
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// 转换金额单位(实际使用中,金额应在服务端计算)
// 详情请参考:<a href="https://docs.antom.com/ac/ref/cc">金额对象使用规则</a>
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();
// 设置金额
Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// 设置结算策略
// 替换为您现有的结算货币
SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
User loginUser = users.get(payment.getUserId());
// 设置买家信息
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// 设置 paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
// 买家已授权
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
paymentMethod.setPaymentMethodId(accessToken);
} else {
// 设置 agreementInfo
// 替换为您的 authState
String authState = UUID.randomUUID().toString();
AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).build();
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);
// 保存与 authState 对应的 paymentMethodType
authStatePayment.put(authState, payment);
// 买家在支付方式客户端注册时使用的登录 ID,登录 ID 可以是买家的电子邮箱地址或手机号码
// 指定此参数可免去买家手动输入登录 ID
if(StringUtil.isNotBlank(loginUser.getPhoneNumber()){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
if(StringUtil.isNotBlank(loginUser.getEmail() && "ALIPAY_HK".equals(payment.getPaymentMethodType())){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
}
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置订单信息
Order order = Order.builder().referenceOrderId(orderId)
.orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// 替换为您的通知 URL
// 或在此配置您的通知 URL:<a href="https://dashboard.antom.com/global-payments/developers/iNotify">通知URL</a>
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com/payment/receivePaymentNotify");
// 替换为您的重定向 URL
alipayPaymentSessionRequest.setPaymentRedirectUrl(
"http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
System.out.println("payment 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(), alipayPaymentSessionResponse));
}请求报文示例:
{
"agreementInfo": {
"authState": "authState001"
},
"order": {
"buyer": {
"referenceBuyerId": "referenceBuyerId001",
"buyerPhoneNo": "852-12****78"
},
"orderAmount": {
"currency": "HKD",
"value": "100"
},
"orderDescription": "orderDescription001",
"referenceOrderId": "referenceOrderId001"
},
"paymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
"paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
"paymentRequestId": "paymentRequestId001",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}响应报文示例:
{
"paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
"paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
"paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}请根据返回的 result.resultStatus 字段值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请更换 paymentRequestId 和 authstate 后重试接口调用。
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// 设置金额
// 需进行金额单位转换(实际金额应在服务端计算)
Amount amount = Amount.builder().currency("HKD").value("98080").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// 设置结算币种
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("USD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// 设置支付方式
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK")
.paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****").build();
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// 设置买家信息
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置订单信息
Order order = Order.builder().referenceOrderId(orderId).
orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// 替换为您的通知地址
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");
// 替换为您的跳转地址
alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// 处理异常情况
}
}
请求报文示例:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "HKD",
"value": "98080"
},
"orderDescription": "antom api testing order",
"referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311a090d"
},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentMethod": {
"paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com",
"paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2dd2b3",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}响应报文示例:
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}请根据返回的 result.resultStatus 字段值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请更换 paymentRequestId 后重试接口调用。
常见问题
问:请求参数的值可以使用中文字符吗?
答:为了避免某些支付方式的不兼容,不要在请求的字段中使用中文字符。
问:如何设置接收支付通知的链接?
答:在 createPaymentSession(快捷支付) 接口中指定参数 paymentNotifyUrl,以接收支付结果的异步通知(notifyPayment),或者在 Antom Dashboard 中配置接收链接。如果请求和 Antom Dashboard 中都指定了链接,请求中指定的值优先。
问:paymentAmount 和 orderAmount 的区别是什么?
答:paymentAmount 是指支付金额,orderAmount 是指订单金额。实际支付金额以 paymentAmount 为准。
问:支付请求中 paymentSessionExpiryTime 超时时间具体指的是什么时间?
答:paymentSessionExpiryTime 表示支付会话创建成功至买家完成支付提交的有效期。买家提交支付后,支付处理超时时间为 10 分钟。因此,买家从会话创建到支付完成的整体时限最长可达 1 小时 10 分钟。
问:在响应报文中有哪些重点关注字段?
答:关注响应报文中的以下字段:
- result.resultStatus:用于判断支付创建会话调用结果。
- paymentSessionData:加密的支付会话数据。将数据传递给前端用于调用 Antom SDK。
- paymentSessionExpiryTime: 支付会话过期时间。
步骤 3:调用 SDK 客户端
在商户服务端获取到 paymentSessionData 后,可通过商户客户端调用 SDK,将收银台跳转至支付方式签约授权页。买家提交支付请求后,SDK 将自动处理加密通信、风控校验、页面跳转及支付指令执行,实现端到端的支付授权闭环流程。
1. 实例化 SDK
- 使用 AMSEasyPayConfiguration来创建 SDK 实例。配置对象包括以下参数:
- 创建 AMSPaymentProtocol 接口的实例,用于处理支付回调的结果,包含以下方法:
实例化 SDK 示例:
#import <AMSComponent/AMSComponent-Swift.h>
AMSEasyPayConfiguration *componentConfig = [AMSEasyPayConfiguration new];
// Alipay 需要添加 fromScheme,该地址用于支付完成后跳回 App 启动页
componentConfig.fromScheme = @"exampleForScheme";
componentConfig.locale = @"en_US";
// 设置沙箱环境,若为空则默认使用生产环境
NSDictionary *options = @{@"sandbox": @"true",
@"notRedirectAfterComplete": @"false"};
componentConfig.options = options;
[[AMSEasyPay shared] initConfiguration:componentConfig];
// 设置回调以监控支付页面的支付事件
[AMSEasyPay shared].paymentDelegate = self;
#pragma AMSPaymentProtocol
- (void)onEventCallback:(NSString *)eventCode eventResult:(AMSEventResult *)eventResult
{
NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
}
下图展示了商户收银台页面拉起半浮层或者跳转到钱包 App 的渲染效果:

- 使用实例对象中的 createComponent创建一个支付组件,其包含的方法如下:
示例代码如下:
[[AMSEasyPay shared] createComponent:sessionData];2. 处理 SDK 回调事件码
onEventCallback
返回的事件码,请根据相关处理建议进行下一步操作。以下示例代码展示了如何处理
onEventCallback
回调函数:-(void)onEventCallback:(NSString *)eventCode eventResult:(AMSEventResult *)eventResult {
if ([[_selectMethod title] isEqualToString:@"ALIPAY_CN"]) {
if ([eventCode isEqualToString:@"SDK_PAYMENT_CANCEL"]) {
NSLog(@"买家取消支付(未提交订单退出支付页面),有效期内可使用原paymentSessionData重新调用SDK,过期则需重新发起创建支付会话请求");
} else if ([eventCode isEqualToString:@"SDK_PAYMENT_SUCCESSFUL"]) {
NSLog(@"支付宝钱包支付成功,请通过Antom服务端获取最终支付结果(查询接口/异步通知)");
} else if ([eventCode isEqualToString:@"SDK_PAYMENT_FAIL"]) {
NSLog(@"T支付宝钱包支付失败,请通过Antom服务端获取最终结果(查询接口/异步通知)");
} else if ([eventCode isEqualToString:@"SDK_PAYMENT_PROCESSING"]) {
NSLog(@"支付宝钱包支付状态未知,请通过Antom服务端获取最终结果(查询接口/异步通知)");
} else if ([eventCode isEqualToString:@"SDK_PAYMENT_ERROR"]) {
NSLog(@"支付宝钱包支付异常,请通过Antom服务端获取最终结果(查询接口/异步通知)");
} else {
NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
}
} else {
// 需要注意,支付成功不会从这个回调函数通知,而是重定向页面到您指定的成功结果页
if ([eventCode isEqualToString:@"SDK_PAYMENT_CANCEL"]) {
NSLog(@"买家取消支付(未提交订单退出支付页面),有效期内可使用原paymentSessionData重新调用SDK,过期则需重新发起创建支付会话请求");
} else if ([eventCode isEqualToString:@"SDK_CALL_URL_SUCCESS"]) {
NSLog(@"成功跳转至钱包APP或商户页面");
} else if ([eventCode isEqualToString:@"SDK_LAUNCH_PAYMENT_APP_ERROR"]) {
NSLog(@"跳转至钱包APP或商户页面失败");
} else if ([eventCode isEqualToString:@"SDK_CREATEPAYMENT_PARAMETER_ERROR"]) {
NSLog(@"输入参数无效,请检查后重试");
} else {
NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
}
}
}3. 销毁组件
在以下情况调用
onDestroy
释放 SDK 组件资源:- 当买家退出支付页面时,完全回收 createPaymentSession(快捷支付) 接口中创建的组件资源。
- 当买家发起多笔支付时,且 initConfiguration中的参数发生变更,回收上一次 createPaymentSession(快捷支付)接口中创建的组件资源。
在以下情况可以不调用
onDestroy
,SDK 会自动释放部分资源(当 iOS SDK AMSComponents 为 1.33.0 及以上版本时)。- 当买家发起多笔支付时,且 initConfiguration中的参数未发生变更。SDK会在支付结束后自行回收部分资源,以重置到createComponent之前的状态。
// 完全回收组件资源
[[AMSEasyPay shared] onDestroy];4. 接收回调函数通知(接入 Alipay 时)
当您接入 Alipay 时,商户客户端可以接收来自回调函数的通知。收到回调函数通知后,使用 AppDelegate 文件中的
openURL
方法处理 Alipay 返回的结果数据:- canProcessOrderWithPaymentResult():用于判断从钱包端回跳至商户端的跳转 URL 是否可用。
- processOrderWithPaymentResult():用于处理从钱包端到商户端的回跳。
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
if ([url.scheme isEqualToString:@"exampleForScheme"]) {
if ([[AMSEasyPay shared] canProcessOrderWithPaymentResult:url]) {
[[AMSEasyPay shared] processOrderWithPaymentResult:url];
}
}
return YES;
}常见问题
问:是否一定要处理 SDK 回调事件?
答:Alipay 需根据事件码处理支付结果展示,但其他支付方式非必选,您可通过回调事件实现日志埋点。
问:一个 AMSEasypay 实例是否可以多次执行 createComponent?
答:不支持,若您要再次发起支付,请创建新的 AMSEasypay 实例。
问:首次支付和后续支付都需要调用 SDK 吗?
答:是的。
用户体验
本 Android 集成指南将协助您快速实现 App 电子钱包及网银支付功能接入,并完成支付页面渲染。




各支付方式在 Android 端的用户体验存在差异,具体交互体验详见下表:
电子钱包
网银转账
电子钱包
以下是电子钱包类支付方式首次支付和后续支付体验图:
首次支付
后续支付
首次支付时,买家可选择立即支付或完成授权流程。成功授权后,后续支付将启用免密功能。
在商户页面完成支付
跳转至支付方式应用程序支付


后续支付仅需提交订单即可完成免密支付。

网银转账
网银转账支付场景下的体验流程如图所示,包含首次支付验证与后续支付简化流程。
首次支付
后续支付
首次支付时,买家可选择立即支付或完成授权流程。成功授权后,后续支付将启用免密功能。

后续支付仅需提交订单即可完成免密支付。

支付流程
首次支付
后续支付
首次支付流程示意图:

- 买家进入商户收银台页面
- 创建支付会话请求
买家确认支付后,调用 createPaymentSession(快捷支付) 接口获取支付会话。 - 调用客户端 SDK
使用支付会话调用 SDK,SDK 将根据支付方式特性自动采集支付要素、渲染支付界面、处理页面跳转并引导买家完成支付。不同支付方式的交互差异详见用户体验。 - 获取授权结果
当授权成功时,Antom 会通过 notifyAuthorization 接口向您发送异步通知。
- 获取支付结果
可通过以下方式同步支付状态:
- 异步通知:在 createPaymentSession(快捷支付) 接口中指定 paymentNotifyUrl 来设置接收异步通知的地址。当支付成功或过期时,Antom 会使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口获取实时状态。
后续支付流程示意图:

- 买家进入商户收银台页面
- 创建支付会话请求
买家确认支付后,调用 createPaymentSession(快捷支付)接口获取支付会话。 - 调用客户端 SDK
使用支付会话调用 SDK,SDK 将根据支付方式特性自动采集支付要素、渲染支付界面、处理页面跳转并引导买家完成支付。不同支付方式的交互差异详见 用户体验。 - 获取支付结果
可通过以下方式同步支付状态:
- 异步通知:在 createPaymentSession(快捷支付)接口中指定 paymentNotifyUrl 来设置接收异步通知的地址。当支付成功或过期时,Antom 会使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口获取实时状态。
集成准备
- 已获得 client ID。
- 已完成密钥配置。
- 已完成异步通知接收地址的配置。
- 集成 Antom 服务端 SDK 资源包,并完成接口库安装及请求示例初始化。具体操作请参阅服务端 SDK。
- 如需使用沙箱环境与生产环境进行联调测试,请提前两个工作日联系 Antom 技术支持申请配置。沙箱环境和生产环境需单独配置。
集成步骤
请按以下流程开始您的集成:
- (可选)预加载
- 创建支付会话
- 调用 SDK
- 获取授权和支付结果
(可选)步骤 1:预加载 SDK 客户端
在加载收银台列表页面时,执行预加载可显著提升收银台页面的渲染性能且无负面性能影响。建议在买家选择支付方式时触发预加载。
请参考以下代码实现预加载:
预加载 SDK
AMSEasyPay.preload(getApplicationContext());
步骤 2:创建支付会话 服务端
当买家选择由 Antom 提供的支付方式进行支付时,您需要收集支付请求 ID、订单金额、支付方式、订单描述、支付重定向页面链接和支付结果通知链接等必要信息。
各支付方式买家支付账户传参格式如下:
首次支付时传入买家支付账号可自动回填买家账号至支付页面,避免手动输入操作。以下是传入和未传入的体验对比图:
传入买家支付账号
未传入买家支付账号
无需输入登录账号。

需手动输入登录账号。

以下是首次支付和后续支付两种不同场景集成示例:
首次支付
后续支付
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// 转换金额单位(实际使用中,金额应在服务端计算)
// 详情请参考:<a href="https://docs.antom.com/ac/ref/cc">金额对象使用规则</a>
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();
// 设置金额
Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// 设置结算策略
// 替换为您现有的结算货币
SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
User loginUser = users.get(payment.getUserId());
// 设置买家信息
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// 设置 paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
// 买家已授权
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
paymentMethod.setPaymentMethodId(accessToken);
} else {
// 设置 agreementInfo
// 替换为您的 authState
String authState = UUID.randomUUID().toString();
AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).build();
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);
// 保存与 authState 对应的 paymentMethodType
authStatePayment.put(authState, payment);
// 买家在支付方式客户端注册时使用的登录 ID,登录 ID 可以是买家的电子邮箱地址或手机号码
// 指定此参数可免去买家手动输入登录 ID
if(StringUtil.isNotBlank(loginUser.getPhoneNumber()){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
if(StringUtil.isNotBlank(loginUser.getEmail() && "ALIPAY_HK".equals(payment.getPaymentMethodType())){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
}
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置订单信息
Order order = Order.builder().referenceOrderId(orderId)
.orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// 替换为您的通知 URL
// 或在此配置您的通知 URL:<a href="https://dashboard.antom.com/global-payments/developers/iNotify">通知URL</a>
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com/payment/receivePaymentNotify");
// 替换为您的重定向 URL
alipayPaymentSessionRequest.setPaymentRedirectUrl(
"http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
System.out.println("payment 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(), alipayPaymentSessionResponse));
}请求报文示例:
{
"agreementInfo": {
"authState": "authState001"
},
"order": {
"buyer": {
"referenceBuyerId": "referenceBuyerId001",
"buyerPhoneNo": "852-12****78"
},
"orderAmount": {
"currency": "HKD",
"value": "100"
},
"orderDescription": "orderDescription001",
"referenceOrderId": "referenceOrderId001"
},
"paymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
"paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
"paymentRequestId": "paymentRequestId001",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}响应报文示例:
{
"paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
"paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
"paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}请根据返回的 result.resultStatus 字段值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请更换 paymentRequestId 和 authstate 后重试接口调用。
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// 设置金额
// 需进行金额单位转换(实际金额应在服务端计算)
Amount amount = Amount.builder().currency("HKD").value("98080").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// 设置结算币种
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("USD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// 设置支付方式
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK")
.paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****").build();
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// 设置买家信息
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置订单信息
Order order = Order.builder().referenceOrderId(orderId).
orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// 替换为您的通知地址
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");
// 替换为您的跳转地址
alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// 处理异常情况
}
}
请求报文示例:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "HKD",
"value": "98080"
},
"orderDescription": "antom api testing order",
"referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311a090d"
},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentMethod": {
"paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com",
"paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2dd2b3",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}响应报文示例:
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}请根据返回的 result.resultStatus 字段值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请更换 paymentRequestId 后重试接口调用。
常见问题
问:请求参数的值可以使用中文字符吗?
答:为了避免某些支付方式的不兼容,不要在请求的字段中使用中文字符。
问:如何设置接收支付通知的链接?
答:在 createPaymentSession(快捷支付)接口中指定参数 paymentNotifyUrl,以接收支付结果的异步通知(notifyPayment),或者在 Antom Dashboard 中配置接收链接。如果请求和 Antom Dashboard 中都指定了链接,请求中指定的值优先。
问:paymentAmount 和 orderAmount 的区别是什么?
答:paymentAmount 是指支付金额,orderAmount 是指订单金额。实际支付金额以 paymentAmount 为准。
问:支付请求中 paymentSessionExpiryTime 超时时间具体指的是什么时间?
答:paymentSessionExpiryTime 表示支付会话创建成功至买家完成支付提交的有效期。买家提交支付后,支付处理超时时间为 10 分钟。因此,买家从会话创建到支付完成的整体时限最长可达 1 小时 10 分钟。
问:在响应报文中有哪些重点关注字段?
答:关注响应报文中的以下字段:
- result.resultStatus: 用于判断支付创建会话调用结果。
- paymentSessionData: 加密的支付会话数据。将数据传递给前端用于调用 Antom SDK。
- paymentSessionExpiryTime: 支付会话过期时间。
步骤 3:调用 SDK 客户端
在商户服务端获取到 paymentSessionData 后,可通过商户客户端调用 SDK,将收银台跳转至支付方式签约授权页。买家提交支付请求后,SDK 将自动处理加密通信、风控校验、页面跳转及支付指令执行,实现端到端的支付授权闭环流程。
1. 实例化 SDK
- 使用 AMSEasyPayConfiguration来创建 SDK 实例。配置对象包括以下参数:
- 创建 setOnCheckoutListener 接口的实例,用于处理后续流程中发生的对应事件,包含以下方法:
实例化 SDK 示例:
// 步骤一: 创建 AMSEasyPayConfiguration 类。
AMSEasyPayConfiguration configuration = new AMSEasyPayConfiguration();
configuration.setLocale(new Locale("en", "US"));
// 设置沙箱环境。如果将其置空,则默认使用线上正式环境。
configuration.setOption("sandbox", "true");
// 默认设置为 false
configuration.setOption("notRedirectAfterComplete", "false");
// 设置回调来监听收银台页面的支付事件。
configuration.setOnCheckoutListener(new OnCheckoutListener() {
@Override
public void onEventCallback(String eventCode, AMSEventResult eventResult) {
// eventCode 请参考本文末的示例代码或事件码列表。
Toast.makeText(activity, "eventCode=" + eventCode + " message=" + message, Toast.LENGTH_SHORT).show();
}
});
// 实例化 AMSEasyPay。
AMSEasyPay checkout = new AMSEasyPay.Builder(activity, configuration).build();
下图展示了商户收银台页面拉起半浮层或者跳转到钱包应用程序的渲染效果:

- 使用实例对象中的createComponent创建一个支付组件,其包含的方法如下:
示例代码如下:
checkout.createComponent(activity, sessionData);2. 处理 SDK 回调事件码
onEventCallback
返回的事件码,请根据相关处理建议进行下一步操作。注意:在 Android Native 环境下,Alipay 仅支持回跳至商户 App 启动页,而非 createPaymentSession(快捷支付) 接口里指定的 paymentRedirectUrl,需通过事件码控制具体跳转页面。
以下示例代码展示了如何处理
onEventCallback
回调函数:configuration.setOnCheckoutListener(new OnCheckoutListener() {
@Override
public void onEventCallback(String eventCode, AMSEventResult eventResult) {
if (selectPayment != null && selectPayment.getPaymentMethodCode().equals("ALIPAY_CN")) {
switch (eventCode) {
case "SDK_PAYMENT_CANCEL":
AlertUtils.showAlertWithMessage(MainActivity.this, "买家已取消支付(买家未提交订单即退出支付页面)。有效期内可使用原paymentSessionData重新调起SDK;若已过期需重新发起createPaymentSession(EasySafePay)请求");
break;
case "SDK_PAYMENT_SUCCESSFUL":
AlertUtils.showAlertWithMessage(MainActivity.this, "支付宝钱包处理支付成功,请通过Antom服务器获取最终支付结果。可通过inquiryPayment接口或notifyPayment接口确认");
break;
case "SDK_PAYMENT_FAIL":
AlertUtils.showAlertWithMessage(MainActivity.this, "支付宝钱包处理支付失败,请通过Antom服务器获取最终支付结果。可通过inquiryPayment接口或notifyPayment接口确认");
break;
case "SDK_PAYMENT_PROCESSING":
AlertUtils.showAlertWithMessage(MainActivity.this, "支付宝钱包支付状态未知,请通过Antom服务器获取最终支付结果。可通过inquiryPayment接口或notifyPayment接口确认");
break;
case "SDK_PAYMENT_ERROR":
AlertUtils.showAlertWithMessage(MainActivity.this, "支付宝钱包支付处理异常,请通过Antom服务器获取最终支付结果。可通过inquiryPayment接口或notifyPayment接口确认");
break;
default:
AlertUtils.showAlertWithMessage(MainActivity.this, "eventCode=" + eventCode + " message=" + eventResult.getMessage());
break;
}
} else {
// 需要注意,支付成功不会从这个回调函数通知,而是重定向页面到您指定的成功结果页
switch (eventCode) {
case "SDK_PAYMENT_CANCEL":
AlertUtils.showAlertWithMessage(MainActivity.this, "买家已取消支付(买家未提交订单即退出支付页面)。有效期内可使用原paymentSessionData重新调起SDK;若已过期需重新发起createPaymentSession请求");
break;
case "SDK_CALL_URL_SUCCESS":
AlertUtils.showAlertWithMessage(MainActivity.this, "成功打开钱包应用或跳转至商户页面");
break;
case "SDK_LAUNCH_PAYMENT_APP_ERROR":
AlertUtils.showAlertWithMessage(MainActivity.this, "打开钱包应用或跳转至商户页面失败");
break;
case "SDK_PAYMENT_SUCCESSFUL":
AlertUtils.showAlertWithMessage(MainActivity.this, "钱包处理支付成功,请通过Antom服务器获取最终支付结果。可通过inquiryPayment接口或notifyPayment接口确认。建议将买家重定向至支付结果页");
break;
case "SDK_PAYMENT_FAIL":
AlertUtils.showAlertWithMessage(MainActivity.this, "钱包处理支付失败,请通过Antom服务器获取最终支付结果。可通过inquiryPayment接口或notifyPayment接口确认。建议将买家重定向至支付结果页");
break;
case "SDK_STATUS_ERROR":
AlertUtils.showAlertWithMessage(MainActivity.this, "支付流程状态异常,请检查是否按正确步骤调用createComponent");
case "SDK_INTEGRATION_ERROR":
AlertUtils.showAlertWithMessage(MainActivity.this, "SDK依赖项不存在,请检查目标模块是否已集成");
break;
case "SDK_CREATEPAYMENT_PARAMETER_ERROR":
AlertUtils.showAlertWithMessage(MainActivity.this, "提供的输入参数无效,请检查参数值后重试");
break;
default:
AlertUtils.showAlertWithMessage(MainActivity.this, "eventCode=" + eventCode + " message=" + eventResult.getMessage());
break;
}
}
}
});3. 销毁组件
在以下情况调用
onDestroy
释放 SDK 组件资源:- 当买家退出支付页面时,完全回收 createPaymentSession(快捷支付) 接口中创建的组件资源。
- 当买家发起多笔支付时,且 AMSEasyPayConfiguration中的参数发生变更,回收上一次 createPaymentSession(快捷支付) 接口中创建的组件资源。
在以下情况可以不调用
onDestroy
,SDK 会自动释放部分资源(当 SDK 为 1.33.0 及以上版本时)。- 当买家发起多笔支付时,且 AMSEasyPayConfiguration中的参数未发生变更。SDK 会在支付结束后自行回收部分资源,以重置到createComponent之前的状态。
以下示例代码展示了如何回收组件:
// 完全回收 SDK 组件资源
checkout.onDestroy();常见问题
问:是否一定要处理 SDK 回调事件?
答:Alipay 需根据事件码处理支付结果展示,但其他支付方式非必选,您可通过回调事件实现日志埋点。
问:一个 AMSEasypay 实例是否可以多次执行 createComponent?
答:不支持,若您要再次发起支付,请创建新的 AMSEasypay 实例。
问:首次支付和后续支付都需要调用 SDK 吗?
答:是的。
用户体验
以下分别为电子钱包和网银转账两种支付类别的用户体验图:
电子钱包
网银转账
电子钱包支付场景下,系统将引导买家在商户页面或支付方式应用程序内完成交易。首次支付验证与后续支付简化流程如图所示:
首次支付
后续支付
首次支付时,买家可以选择直接支付或者授权流程。当用户完成授权后,后续支付可以使用免密支付能力。
商户页面完成支付
跳转到支付方式页面完成支付


买家仅需提交订单即可完成免密支付。

网银转账支付场景下的体验流程如图所示,包含首次支付验证与后续支付简化流程。
首次支付
后续支付
在首次支付时,买家完成支付授权流程以确保后续免密支付。

后续无需验证码即可完成支付。

支付流程
以下是首次支付和后续支付流程示意图:
首次支付
后续支付
首次支付流程示意图

- 买家进入商户收银台页面
- 当买家选择支付方式后,预加载Antom SDK
- 创建支付会话请求
在买家点击支付按钮后,您可以通过调用 createPaymentSession(快捷支付) 接口来获取支付会话。 - 调用客户端 SDK
在客户端通过支付会话调用 SDK。SDK 将会基于支付方式的特点收集支付要素、展示支付页面信息、进行重定向等,并引导买家完成支付。不同支付方式差异请参考支付方式特性-体验差异处理。 - 获取授权结果
- 获取支付结果
通过以下两种方法获取支付结果:
- 异步通知:在 createPaymentSession(快捷支付) 接口中指定 paymentNotifyUrl 或门户设置接收异步通知的地址。当支付完成后,Antom 会使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口检查支付状态。
后续支付流程示意图

- 买家进入商户收银台页面
- 当买家选择支付方式后,预加载Antom SDK
- 创建支付会话请求
在买家选择支付方式并提交订单后,您可以通过调用 createPaymentSession(快捷支付) 接口来获取支付会话。 - 调用客户端 SDK
在客户端通过支付会话调用 SDK。SDK 会基于支付方式的特点直接完成支付或者收集支付要素、重定向等,直至买家完成支付。不同支付方式差异请参考支付方式特性-体验差异处理。 - 获取支付结果
通过以下两种方法获取支付结果:
- 异步通知:在 createPaymentSession(快捷支付) 接口中指定 paymentNotifyUrl 来设置接收异步通知的地址。当支付完成后, Antom 将使用 notifyPayment 接口向您发送异步通知。
- 同步查询:调用 inquiryPayment 接口检查支付状态。
集成准备
- 已获得 client ID。
- 已完成密钥配置。
- 已完成异步通知接收地址的配置。
- 集成 Antom 服务端 SDK 资源包,并完成接口库安装及请求示例初始化。具体操作请参阅服务端 SDK。
- 如需使用沙箱环境与生产环境进行联调测试,请提前两个工作日联系 Antom 技术支持申请配置。沙箱环境和生产环境需单独配置。
版本要求
- iOS 版本要求:
- 安装 Xcode 12 或更高版本。
- 使用 iOS 11 或更高版本。
- Android 版本要求:使用 Android 4.4(API level 19) 或更高版本。
注意:暂不支持 Flutter 和 React Native(RN)开发框架。
集成步骤
通过以下步骤开始您的集成:
- (可选)预加载
- 创建支付会话
- 调用SDK
- 获取授权和支付结果
(可选)步骤 1:预加载 SDK 客户端
在加载收银台列表页面时,执行预加载可显著提升收银台页面的渲染性能且无负面性能影响。建议在买家选择支付方式时触发预加载。
请参考以下代码实现预加载:
AMSEasypay.preload();步骤 2:创建支付会话 服务端
首次支付和后续支付调用接口参数说明:
各支付方式买家支付账户传参格式如下:
首次支付和后续支付两种不同场景集成代码示例:
首次支付
后续支付
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// 转换金额单位(实际使用中,金额应在服务端计算)
// 详情请参考:<a href="https://docs.antom.com/ac/ref/cc">金额对象使用规则</a>
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();
// 设置金额
Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// 设置结算策略
// 替换为您现有的结算货币
SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
User loginUser = users.get(payment.getUserId());
// 设置买家信息
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// 设置 paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
// 买家已授权
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
paymentMethod.setPaymentMethodId(accessToken);
} else {
// 设置 agreementInfo
// 替换为您的 authState
String authState = UUID.randomUUID().toString();
AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).build();
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);
// 保存与 authState 对应的 paymentMethodType
authStatePayment.put(authState, payment);
// 买家在支付方式客户端注册时使用的登录 ID,登录 ID 可以是买家的电子邮箱地址或手机号码
// 指定此参数可免去买家手动输入登录 ID
if(StringUtil.isNotBlank(loginUser.getPhoneNumber()){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
if(StringUtil.isNotBlank(loginUser.getEmail() && "ALIPAY_HK".equals(payment.getPaymentMethodType())){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
}
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置订单信息
Order order = Order.builder().referenceOrderId(orderId)
.orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// 替换为您的通知 URL
// 或在此配置您的通知 URL:<a href="https://dashboard.antom.com/global-payments/developers/iNotify">通知URL</a>
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com/payment/receivePaymentNotify");
// 替换为您的重定向 URL
alipayPaymentSessionRequest.setPaymentRedirectUrl(
"http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
System.out.println("payment 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(), alipayPaymentSessionResponse));
}请求报文示例:
{
"agreementInfo": {
"authState": "authState001"
},
"order": {
"buyer": {
"referenceBuyerId": "referenceBuyerId001",
"buyerPhoneNo": "852-12****78"
},
"orderAmount": {
"currency": "HKD",
"value": "100"
},
"orderDescription": "orderDescription001",
"referenceOrderId": "referenceOrderId001"
},
"paymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
"paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
"paymentRequestId": "paymentRequestId001",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}响应报文示例,包含以下重点参数:
- paymentSessionData:加密的支付会话数据。将数据传递给前端用于调用 Antom SDK。
- paymentSessionExpiryTime:支付会话的过期时间。
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}请根据返回的 result.resultStatus 字段值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请更换 paymentRequestId 和 authstate 后重试接口调用。
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// 替换为您的 paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// 设置金额
// 转换金额单位(实际使用中,金额应在服务端计算)
Amount amount = Amount.builder().currency("HKD").value("98080").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// 设置结算币种
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("USD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// 设置 paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK")
.paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****").build();
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// 设置买家信息
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// 替换为您的 orderId
String orderId = UUID.randomUUID().toString();
// 设置订单信息
Order order = Order.builder().referenceOrderId(orderId).
orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// 替换为您的通知 URL
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");
// 替换为您的重定向 URL
alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// 处理错误情况
}
}请求报文示例:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "HKD",
"value": "98080"
},
"orderDescription": "antom api testing order",
"referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311****"
},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentMethod": {
"paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com",
"paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2d****",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}响应报文示例,包含以下重点参数:
- paymentSessionData:加密的支付会话数据。将数据传递给前端用于调用 Antom SDK。
- paymentSessionExpiryTime:支付会话的过期时间。
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}请根据返回的 result.resultStatus 字段值执行下一步操作:
注意:若您未收到响应,可能是网络超时导致,请更换 paymentRequestId 后重试接口调用。
常见问题
问:请求参数的值可以使用中文字符吗?
答:为了避免某些支付方式的不兼容,不要在请求的字段中使用中文字符。
问:如何设置接收支付通知的链接?
答:在 createPaymentSession(快捷支付) 接口中指定参数 paymentNotifyUrl,以接收支付结果的异步通知(notifyPayment),或者在 Antom Dashboard 中配置接收链接。如果请求和 Antom Dashboard 中都指定了链接,请求中指定的值优先。
问:paymentAmount 和 orderAmount 的区别是什么?
答:paymentAmount 是指支付金额,orderAmount 是指订单金额。实际支付金额以 paymentAmount 为准。
问:支付请求中 paymentSessionExpiryTime 超时时间具体指的是什么时间?
答:paymentSessionExpiryTime表 示支付会话创建成功至买家完成支付提交的有效期。买家提交支付后,支付处理超时时间为 10 分钟。因此,买家从会话创建到支付完成的整体时限最长可达 1 小时 10 分钟。
步骤 3:调用 SDK 客户端
在商户服务端获取到 paymentSessionData 后,可通过商户客户端调用 SDK,将收银台跳转至支付方式签约授权页。买家提交支付请求后,SDK 将自动处理加密通信、风控校验、页面跳转及支付指令执行,实现端到端的支付授权闭环流程。
1. 实例化 SDK
- 使用 AMSEasyPay来创建 SDK 实例。配置对象包括以下参数:
以下示例代码展示了如何通过 npm 或 CDN 实例化 SDK:
npm
CDN
import { AMSEasyPay } from '@alipay/ams-checkout' //包管理
const checkoutApp = new AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({code, message})=>{},
});const checkoutApp = new window.AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({code, message})=>{},
});- 使用实例对象中的 createComponent创建一个支付组件,涉及的参数如下:
创建支付组件示例:
async function create(sessionData) {
await checkoutApp.createComponent({
sessionData: sessionData,
isNativeAppWebview: true, // 默认为 false,表示商户通过 H5 网页集成网页版 SDK
notRedirectAfterComplete: false // 默认设为 false,表示支付完成后将重定向至您的页面
});
}- 监听事件码处理跳转事件
通过监听 SDK_REDIRECT 事件码处理后续流程,代码示例如下:
import { AMSEasyPay } from '@alipay/ams-checkout' //包管理
const checkoutApp = new AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({code, message, result}) => {
switch (code) {
case 'SDK_REDIRECT':
// 处理跳转逻辑
const redirectUrls = result?.redirectUrls || {};
const jsonString = JSON.stringify(redirectUrls);
// 判断当前环境espJSBridge是否为空
if (window.espJSBridge) {
// 调用espJSBridge的sdkRedirect方法,传入重定向信息,此方法为参考,也可按照商户本身与native的通信方式进行数据传递
window.espJSBridge.sdkRedirect(jsonString)
// 数据传递完成后,进行组件的回收操作
checkoutApp.unmount();
}
break;
default:
console.log(code);
}
},
});- 使用 WebView 容器处理跳转事件
使用 WebView 容器处理 App 内跳转事件,以下分别为 iOS 和 Android 端示例代码:
iOS
Android
iOS
// 步骤1:创建webview容器
let url = "https://www.merchantWeb.com"
let webView = WKWebView()
webView.load(URLRequest(url: url))
webView.configuration.userContentController.addUserScript(
WKUserScript(
source: "window.espJSBridge = { sdkRedirect: function(message) { window.webkit.messageHandlers.espJSBridge.postMessage(message); } }",
injectionTime: .atDocumentStart,
forMainFrameOnly: true
)
)
webView.configuration.userContentController.add(self, name: "espJSBridge")
// 步骤2:处理跳转事件
extension DemoViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
// 监听跳转事件
if message.name == "espJSBridge",
let bodyString = message.body as? String,
let bodyData = bodyString.data(using: .utf8),
let body = try? JSONSerialization.jsonObject(with: bodyData, options: []) as? [String: Any]
{
let applinkUrl = body["applinkUrl"] as? String
let schemeUrl = body["schemeUrl"] as? String
let normalUrl = body["normalUrl"] as? String
// 跳转链接
// 尝试跳转applinkUrl
tryRedirect(url: applinkUrl) { [weak self] success in
// 如果失败,尝试跳转schemeUrl
if !success {
self?.tryRedirect(url: schemeUrl) { [weak self] success in
// 如果失败,尝试跳转normalUrl
if !success {
self?.tryRedirect(url: normalUrl) { _ in }
}
}
}
}
}
}
}
func tryRedirect(url: String?, completion: @escaping (Bool) -> Void) {
guard let url = url, let url = URL(string: url) else {
completion(false)
return
}
UIApplication.shared.open(url) { success in
completion(success)
}
}Android
// 步骤1:创建webview容器
WebView webView;
webView = findViewById(R.id.webView);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JSBridgeInterface(this), "espJSBridge");
webView.loadUrl(url);
// 步骤2:处理跳转事件
public class JSBridgeInterface {
private Context mContext;
public JSBridgeInterface(Context context) {
mContext = context;
}
// 监听跳转事件
@JavascriptInterface
public void sdkRedirect(String redirectInfo) {
JSONObject jsonObject = JSONObject.parseObject(redirectInfo);
String schemeUrl = jsonObject.getString("schemeUrl");
String applinkUrl = jsonObject.getString("applinkUrl");
String normalUrl = jsonObject.getString("normalUrl");
// 尝试跳转schemeUrl
if (openRedirectionUrl(schemeUrl, true)) {
return;
}
// 尝试跳转applinkUrl
if (openRedirectionUrl(applinkUrl, false)) {
return;
}
// 尝试跳转normalUrl
if (openRedirectionUrl(normalUrl, false)) {
return;
}
showToast(mContext, "Failed to open URL");
}
private boolean openRedirectionUrl(String url, boolean isScheme) {
if (TextUtils.isEmpty(url)) {
return false;
}
try {
Intent intent = isScheme ? Intent.parseUri(url, Intent.URI_INTENT_SCHEME) : new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(mContext, intent, null);
return true;
} catch (Exception exception) {
showToast(mContext, exception.getMessage()); // 显示提示信息
return false;
}
}
private void showToast(Context context, String message) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}2. 处理 SDK 回调事件码
下列是
onEventCallback
返回的事件码:以下示例代码展示了如何处理回调函数
onEventCallback
:function onEventCallback({ code, result }) {
switch (code) {
case 'SDK_REDIRECT':
// 处理跳转逻辑
break;
case 'SDK_PAYMENT_CANCEL':
// 在有效期内,可以使用 paymentSessionData 重新调用SDK
break;
default:
break;
}
}3. 销毁组件
在以下情况下,调用
unmount
方法来释放 SDK 组件资源:- 当买家切换视图离开结账页面时,释放 createPaymentSession(快捷支付) 中创建的组件资源。
- 当买家发起多次支付时,释放之前 createPaymentSession(快捷支付) 中创建的组件资源。
- 在获取最终支付结果后释放组件资源。
// 完全回收组件资源
checkoutApp.unmount();常见问题
问:是否一定要处理 SDK 回调事件?
答:需要根据 isNativeAppWebview 的值来判断:
- 当 isNativeAppWebview 为 true时需要对关键回调进行处理。一般分为两类:
- 关键回调(如支付跳转 SDK_REDIRECT):必须处理,否则支付流程会中断。
- 其他回调:可选处理,您可以使用回调事件做一些日志埋点。
- 当 isNativeAppWebview 为 false时可选处理,您可以使用回调事件做一些日志埋点。
问:一个
AMSEasypay
的实例是否可以多次执行 createComponent
?答:不支持,若您要再次发起支付,请创建新的
AMSEasypay
实例。
问:首次支付和后续支付都需要调用 SDK 吗?
答:是的。
步骤 4:获取授权和支付结果
首次支付将返回授权及支付结果,后续支付仅返回支付结果。以下是常见场景:
获取授权结果
获取支付结果
获取授权结果
- 配置接收异步授权通知的 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:
- 订单级通知配置:通过 createPaymentSession(快捷支付)接口请求中的 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 小时。
问:授权通知和支付结果通知是分开的,授权通知一定是比支付结果通先收到吗?
答:由于网络稳定性不可控,可能会出现授权通知比支付结果通知晚到的情况。
问:是否支持授权查询接口?
答:目前暂未支持该能力。
问:在响应异步通知时,我需要添加数字签名吗?
支付后集成
取消授权
取消交易
退款
账单
最佳实践
- 智能风控服务
- 安全扩展包
- 结果页跳转后的订单查询
- 商户侧主动取消交易
- 支付失败重试