快捷支付(Web/WAP)
注意:本文档已停止维护并下线归档,请访问 https://docs.antom.com/ 获取最新内容。
本文为您介绍支持从桌面浏览器或移动浏览器接收付款的集成解决方案。集成后,您可以接入数字钱包、银行卡和银行转账等多种支付方式。
用户体验
以下图片分别展示了钱包和银行转账的用户体验。在首次支付时,买家可以启用免密支付,这样后续支付无需再输入支付密码。后续支付的全流程都将在您的网站或应用上进行。
钱包
当使用钱包付款时,整个支付流程会保留在您的网站或应用程序内,买家可以在首次付款时启用免密支付,后续付款无需再输入支付密码。
第一次使用钱包支付
在首次支付时,买家完成支付授权流程以确保后续免密支付。
银行转账
对于银行转账支付方式,以下图表展示了首次支付和后续支付的用户体验。
首次使用银行转账支付
在首次支付时,用户需要输入支付密码和验证码。
支付流程
首次支付
当买家选择 Antom 提供的支付方式时,您需要采集支付请求 ID、订单金额、支付方式、订单详情、支付重定向链接和支付结果通知链接等必要信息。然后调用 支付会话创建(快捷支付)接口来下单,并调用 Antom SDK 中的相关方法完成支付流程。
- 买家进入结账页面
- 创建支付会话请求
在买家选择支付方式并提交订单后,您可以通过调用 支付会话创建(快捷支付)接口来获取支付会话。 - 调用客户端 SDK
在客户端通过支付会话调用 SDK。SDK 将会基于支付方式的特点收集支付要素、展示代码信息、进行重定向、调用,并引导买家完成支付。 - 获取授权结果
- 获取支付结果
通过以下两种方法获取支付结果:
- 异步通知:在 支付会话创建(快捷支付)接口中指定 paymentNotifyUrl 来设置接收异步通知的地址。当支付成功或过期时, Antom 会使用 支付通知 接口向您发送异步通知。
- 同步查询:调用 支付结果查询 接口检查支付状态。
集成步骤
通过以下步骤开始您的集成:
- 创建支付会话
- 调用 SDK
- 获取授权或支付结果
步骤 1:创建支付会话
当买家选择由 Antom 提供的支付方式时,您需要收集支付请求 ID、订单金额、支付方式、订单描述、支付重定向页面链接和支付结果通知链接等必要信息。随后,通过以下步骤调用 支付会话创建(快捷支付)接口来创建支付会话:
- 安装接口库
- 初始化请求实例
- 调用 支付会话创建(快捷支付)接口
注意:Antom 提供多种语言的服务器端接口库。以下代码以 Java 为例,需要安装 Java 6 或更高版本。
安装接口库
您可以在 GitHub 上找到最新版本。
<dependency>
<groupId>com.alipay.global.sdk</groupId>
<artifactId>global-open-sdk-java</artifactId>
<version>2.0.44</version>
</dependency>
初始化请求实例
创建一个单例资源以向 Antom 发起请求。
import com.alipay.global.api.AlipayClient;
import com.alipay.global.api.DefaultAlipayClient;
import com.alipay.global.api.model.constants.EndPointConstants;
public class Sample {
public static final String CLIENT_ID = "";
public static final String ANTOM_PUBLIC_KEY = "";
public static final String MERCHANT_PRIVATE_KEY = "";
private final static AlipayClient CLIENT = new DefaultAlipayClient(
EndPointConstants.SG, MERCHANT_PRIVATE_KEY, ANTOM_PUBLIC_KEY, CLIENT_ID);
}
创建支付会话
首次支付
调用 支付会话创建(快捷支付)接口指定以下参数来创建支付会话:
参数 | 是否必填 | 说明 |
paymentRedirectUrl | ✅ | 支付完成后,页面将跳转至此商户传入的网址。有以下两种方式:
iOS 系统网页浏览器
iOS 系统 App
Android 系统网页浏览器
Android 系统 App
|
authState | ✅ | 您用于发起授权而分配的专属ID,在后续免密支付中获取令牌。该参数仅在首次支付时传递,后续支付无需传递此参数。 |
paymentNotifyUrl | ✅ | 支付结果通知地址。这个地址必须是 HTTPS。 |
paymentSessionExpiryTime | 支付会话超时。默认为 1 小时,可以设置在 1 小时内。该值的格式遵循 ISO 8601 标准。例如,2019-11-27T12:01:01+08:00。 | |
userLoginId | 买家支付方式的登录账户,可能是买家的邮箱地址或者手机号码。 | |
order.buyer: referenceBuyerId/buyerPhoneNo/buyerEmail | 传递买家信息以供风险决策。传递 referenceBuyerId、buyerPhoneNo、buyerEmail 其中一个参数即可。 |
以上参数并非完整参数,请参阅 支付会话创建(快捷支付)接口以获取完整参数列表以及特定支付方式的额外要求。
以下示例代码展示如何调用 支付会话创建(快捷支付)接口:
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// replace with your paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// set amount
// you should convert amount unit(in practice, amount should be calculated on your serverside)
Amount amount = Amount.builder().currency("HKD").value("98080").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
//set settlement currency
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("USD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK").build();
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// set agreementInfo
// replace with your authState
String authState = UUID.randomUUID().toString();
// The login ID that the user used to register in the payment method client. The login ID can be the user's email address or phone number.
// Specify this parameter to free users from manually entering their login IDs.
String userLoginId = "852-91234567";
AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).userLoginId(userLoginId).build();
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set order Info
Order order = Order.builder().referenceOrderId(orderId).
orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// replace with your notify url
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");
// replace with your redirect url
alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// handle error condition
}
}
以下代码是请求报文的示例:
{
"agreementInfo": {
"authState": "2b7a4a24-b909-4633-8ffe-8ed3648e99b4",
"userLoginId": "852-91234567"
},
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "HKD",
"value": "98080"
},
"orderDescription": "antom api testing order",
"referenceOrderId": "1a57b8cd-9a25-4d44-94f7-3467a4ebe532"
},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com",
"paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a792a",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}
以下代码是包含了以下参数的响应示例:
- paymentSessionData: 需要转发给您客户端的支付会话数据。
- paymentSessionExpiryTime: 支付会话的过期时间。
{
"paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
"paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
"paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
常见问题
问:请求参数的值可以使用中文字符吗?
答:为了避免某些支付方式的不兼容,不要在请求的字段中使用中文字符。
问:如何设置接收支付通知的链接?
答:在 支付会话创建(快捷支付)接口中指定参数 paymentNotifyUrl,以接收支付结果的异步通知(支付通知),或者在 Antom Dashboard 中配置接收链接。如果请求和 Antom Dashboard 中都指定了链接,请求中指定的值优先。
步骤 2:调用SDK
安装
在开始集成之前,请确保您已完成以下环境准备:
- 处理兼容性问题:为 Internet Explorer 和其他旧版浏览器提供相应的 Polyfills。我们建议您在构建项目时使用 babel-preset-env 来解决浏览器兼容性问题。
- 使用以下推荐的浏览器版本:
- 对于移动浏览器:
- iOS 11及更高版本。
- Android 5.0及更高版本。
- 对于电脑浏览器,使用以下推荐版本:
请查阅 Web/WAP 端集成 SDK 资源包文档来集成 SDK 资源包。
实例化 SDK
通过 AMSEasyPay
创建 SDK 实例化并设置基础配置。配置对象包括以下参数:
参数 | 是否必填 | 说明 |
environment | ✅ | 用于指定环境信息。有效值有:
|
locale | 用于指定语言信息。根据支付方式所在地区选择合适的值。此参数的有效值如下所示,如果使用了以下列表中未列出的值,将使用本地语言代替。
| |
analytics | 用于配置和分析数据。有效值有:
| |
onLog | 在 SDK 运行期间,用于生成关于日志和接口异常错误信息的回调函数。 | |
onEventCallback | 当一个支付时间发生在 SDK 运行时,返回指定事件代码的回调函数。例如支付结果或格式提交错误。 |
以下示例代码展示了如何获取浏览器语言:
let language = navigator.language || navigator.userLanguage;
language = language.replace("-", "_"); //将 "-" 替换成 "_"
以下示例代码展示了如何通过 npm 实例化 SDK:
import { AMSEasyPay } from '@alipay/ams-checkout' //包管理
const checkoutApp = new AMSEasyPay({
environment: "sandbox",
locale: "en_US",
analytics: {
enabled: true
},
onLog: ({code, message})=>{},
onClose:()=>{
//关闭半屏弹窗
},
onEventCallback: ({code, message})=>{},
});
以下示例代码展示了如何通过 CDN 实例化 SDK:
const checkoutApp = new window.AMSEasyPay({
environment: "sandbox",
locale: "en_US",
analytics: {
enabled: true
},
onLog: ({code, message})=>{},
onClose:()=>{
//关闭半屏弹窗 Close the half-screen popup
},
onEventCallback: ({code, message})=>{},
});
调用 SDK
使用实例对象中的createComponent
去创建一个支付组件:
参数 | 是否必填 | 说明 |
sessionData | ✅ | 使用 sessionData 参数创建配置对象:将 支付会话创建(快捷支付)接口响应中的 paymentSessionData 完整数据作为此参数的值。 |
appearance | 自定义外观主题配置,其中包含以下子参数:
| |
isAppWebview | 表示是否为 App 的网页视图。有效值为:
|
以下示例代码展示了如何渲染组件:
async function create(sessionData) {
await checkoutApp.createComponent({
sessionData: sessionData,
appearance:{
showLoading: true, // 默认为true,展示初始化加载动画
},
isAppWebview: false // 默认为false,表示商户通过 H5 网页集成网页版 SDK
});
}
调用实例对象中的 unmount
函数进行 SDK 组件的资源回收,请在以下两种场景中调用:
- 当买家退出支付页面时,回收 支付会话创建(快捷支付)接口中创建的组件资源。
- 当买家发起多笔支付时,回收上一次 支付会话创建(快捷支付)接口中创建的组件资源。
//回收组件资源
checkoutApp.unmount();
常见问题
问:当我收到
SDK_CREATEPAYMENT_PARAMETER_ERROR
时能做什么?答:当您收到这个事件代码时,请检查 sessionData 是否传入及是否正确。
问:当我收到
SDK_PAYMENT_ERROR
或者发生了视图渲染错误时能做什么?答:检查接口初始化时网络请求是否存在任何异常,比如网络连接超时。确保创建支付会话请求的环境与用于 SDK 实例的环境一致。检查 支付会话创建(快捷支付)接口中的参数是否正确传递。如果接口异常持续存在,请随时联系我们以获得进一步的故障排查帮助。
步骤 3:获取授权或支付结果
对于首次支付,您可以获取授权和支付结果,而对于后续支付,仅提供支付结果。
您可以通过以下方法之一获取授权或支付结果:
- 接收异步通知
- 查询结果
接收异步通知
获取授权结果
授权成功后, Antom 会通过 授权结果通知 接口给您发送异步通知。当您收到通知,您需要按照返回收到确认信息返回响应。同时,您必须在系统中更新买家的授权状态,并在您的授权管理页面上显示从通知中获取的买家无敏感信息账户。
以下代码是通知请求的示例:
{
"accessToken": "28288803001319861727421828000Cv96OFlYoi17100****",
"accessTokenExpiryTime": 2145916817000,
"authState": "36a38e87-0453-495e-ad17-b46553b918da",
"authorizationNotifyType": "TOKEN_CREATED",
"userLoginId": "852-91****67",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
如何验证通知的签名并对此作出响应,请参阅签名与验签。
问:支付结果通知何时发送?
答:这取决于支付是否完成:
- 如果支付成功完成,Antom通常会在 3 到 5 秒内发送异步通知。对于像 OTC 这样的支付方式,通知可能会稍有延迟。
- 如果支付未完成,Antom需要先关闭订单,然后发送异步通知。不同支付方式关闭订单所需的时间会有所不同,通常默认为 14 分钟。
问:异步通知会被重新发送吗?
答:是的,对于以下情况,异步通知将在 24 小时内自动重新发送:
- 如果由于网络原因没有收到异步通知;
- 如果您收到 Antom 的异步通知,但您没有按照处理通知的示例代码格式进行响应。
通知可以重发最多 8 次,或者直到收到正确的响应以终止传递。发送间隔如下:0 分钟,2 分钟,10 分钟,10 分钟,1 小时,2 小时,6 小时,15 小时。
问:在响应异步通知时,我需要添加数字签名吗?
答:如果您收到 Antom 的异步通知,您需要按照处理通知的示例代码格式返回响应,但不需要对响应进行签名。
问:在支付结果通知中,我需要使用哪些关键参数?
答:请注意以下关键参数:
- result:表示订单的支付结果。
- paymentRequestId:用于咨询、取消和对账的支付请求 ID。
- paymentId:由 Antom 生成的支付订单 ID,用于退款和对账。
- paymentAmount:表示支付金额。
问:在授权结果通知中,我需要使用哪些关键参数?
答:请注意以下关键参数:
- result:表示订单的支付结果。
- authState:由商户生成的资产绑定请求 ID。
- accessToken:由 Antom 生成的代扣 ID,用于后续支付。
- userLoginId:用户的无敏感信息账户 ID。
支付结果查询
您可以调用 支付结果查询 接口来发起对订单结果的查询。
参数 | 是否必填 | 说明 |
paymentRequestId | 由您生成的支付请求 ID。 |
以上参数并非完整参数,请参考 支付结果查询 接口获取完整参数集以及特定支付方式的额外要求。
以下示例代码展示了如何调用 支付结果查询 接口:
public static void inquiryPayment() {
AlipayPayQueryRequest alipayPayQueryRequest = new AlipayPayQueryRequest();
// replace with your paymentRequestId
alipayPayQueryRequest.setPaymentRequestId("yourPaymentRequestId");
AlipayPayQueryResponse alipayPayQueryResponse = null;
try {
alipayPayQueryResponse = CLIENT.execute(alipayPayQueryRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// handle error condition
}
}
以下是请求报文的示例:
{
"paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a792a"
}
以下是响应报文的示例:
{
"cardInfo": {},
"paymentResultCode": "SUCCESS",
"paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a792a",
"paymentResultInfo": {},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"result": {
"resultStatus": "S",
"resultCode": "SUCCESS",
"resultMessage": "success."
},
"actualPaymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentId": "202409271940108001001881E0211235544",
"paymentResultMessage": "success",
"pspCustomerInfo": {
"pspName": "ALIPAY_HK"
},
"paymentTime": "2024-09-27T00:23:46-07:00",
"customsDeclarationAmount": {},
"paymentStatus": "SUCCESS"
}
常见问题
问:我应该多久调用一次支付结果查询接口?
答:以 2 秒为间隔持续调用 支付结果查询 接口,直到获取最终的支付结果或收到异步支付结果通知。
问:我在通知中需要使用哪些关键参数?
答:请注意这些关键参数:
- result:表示此 支付结果查询 接口调用的结果,需要根据 paymentStatus 来判断订单状态:
SUCCESS
和FAIL
表示最终结果;PROCESSING
表示处理中。
- paymentAmount:表示支付的金额。
示例代码
使用客户端 SDK 的完整示例代码:
// 步骤一:实例化SDK
const checkoutApp = new window.AMSCashierPayment({
environment: "sandbox",
locale: "en_US",
onLog: ({code, message}) => {},
onEventCallback: ({code, message}) => {},
});
// 处理卡支付按钮事件
document
.querySelector("#your form id")
.addEventListener("submit", handleSubmit);
async function handleSubmit() {
// 步骤二:服务端调用支付会话创建接口,获取paymentSessionData
async function getPaymentSessionData() {
const url = "Fill in the server address";
const config = {
// 填写请求配置
};
const response = await fetch(url, config);
// 获取响应中的paymentSessionData参数值
const { paymentSessionData } = await response.json();
return paymentSessionData;
}
const paymentSessionData = await getPaymentSessionData();
// 步骤三:创建渲染卡组件
await checkoutApp.createComponent({
sessionData: paymentSessionData,
appearance:{
showLoading: true, // 默认为true,表示展示初始化加载动画
},
});
// 步骤三:创建渲染卡组件
await checkoutApp.createComponent({
sessionData: paymentSessionData,
appearance:{
showLoading: true, // 默认为true,展示初始化加载动画
},
isAppWebview: false // 默认为false,表示商户通过 H5 网页集成网页版 SDK
});
}
自定义加载动画的示例代码
银行卡支付场景支持配置自定义加载动画:
- 当渲染组件时,将 showLoading 配置为
false
。 - 当调用
createComponent
方法时,在当前页面渲染自定义加载动画。 - 监听
onEventCallback
事件。
- 当您收到
SDK_START_OF_LOADING
事件代码时,显示您的自定义加载动画。 - 当您收到
SDK_END_OF_LOADING
事件代码时,关闭您的自定义加载动画。
async function create(sessionData) {
await checkoutApp.createComponent({
sessionData: sessionData,
appearance:{
showLoading: true, // 默认为true,展示初始化加载动画
},
isAppWebview: false // 默认为false,表示商户通过 H5 网页集成网页版 SDK
});
}
事件码
您可能会看到两种类型的事件码:
- 状态码:在组件运行生命周期内,通过
onEventCallback
回调函数返回。 - 错误码:在组件初始化阶段,通过
onEventCallback
或onError
回调函数返回。
类型 | 代码 | 说明 | 后续操作 |
状态码 | SDK_START_OF_LOADING | 配置 | 无需进一步操作。 |
SDK_END_OF_LOADING | 配置 | 无需进一步操作。 | |
SDK_CALL_URL_ERROR | 此事件码代表以下事件信息中的一种情况:
Web/WAP 场景下通常不会出现跳转异常,如果出现异常建议您校验重定向链接。在 App 场景下,如果频繁出现跳转异常,请联系 Antom 技术支持,排查跳转或唤端问题。 | 无需进一步操作。 | |
SDK_PAYMENT_CANCEL | 表示用户取消支付,即用户未提交订单退出支付页面。您可使用有效期内的 paymentSessionData 重新调用 SDK。如已过期,需要重新发起 支付会话创建(快捷支付)请求。 | 无需进一步操作。 | |
错误码 | SDK_INTERNAL_ERROR | SDK 内部错误。 | 请联系 Antom 技术支持。 |
SDK_CREATEPAYMENT_PARAMETER_ERROR |
函数传入参数异常。 | 请检查参数是否正确并重新初始化组件。 | |
SDK_INIT_PARAMETER_ERROR |
函数传入参数异常。 | 请检查参数是否正确并重新实例化 SDK。 | |
SDK_CREATECOMPONENT_ERROR | 组件初始化异常。 | 请联系 Antom 技术支持。 | |
SDK_SUBMIT_NETWORK_ERROR | 因网络原因,接口调用失败。在 | 请尝试再次提交。 |