APM 支付
收银台支付可以帮助您的网站或应用程序开始在线接受支付。本文介绍如何集成以支持从桌面浏览器,移动浏览器或应用中接收支付。集成后,您可以访问各种支付方式,如数字钱包、银行卡和银行转账。
用户体验
Web 用户体验
对于桌面网站发起的支付,您需要将买家重定向到重定向链接或者在新的标签页打开链接。
注意:如果您希望为买家提供 Alipay+ 统一支付体验,而不是上述用户体验,请参阅 Alipay+ 统一支付收银台,并联系 Antom 技术支持获取更多集成详情。
支付流程
每种支付方式的支付流程由以下步骤组成:
- 买家进入结账页面。
- 创建支付请求。
买家选择支付方式并提交订单后,调用 支付(收银台)接口以获取支付链接来完成支付。 - 处理支付推进链接。
将支付推进链接返回给客户端。需要将买家重定向到支付推进链接。支付推进链接根据支付方式的特性执行不同的操作,如收集信息、重定向用户、调用应用、显示二维码和进行验证。 - 获取支付结果。
通过以下两种方法之一获取支付结果:
集成步骤
开始集成,请按照以下步骤操作:
- (可选)添加支付方式列表
- 调用 支付(收银台)接口获取支付推进链接
- 获取支付结果
步骤 1:(可选)添加支付方式列表
添加您计划集成的支付方式的标识和名称。这使得买家能轻松选择他们偏好的支付方式。您可以通过以下两种方式获取标识和名称:
- 联系 Antom 技术支持。Alipay+ 支付方式的标识需要符合 Alipay+ 品牌规范,您可以根据需要的尺寸和风格自动生成。更多信息请参考品牌资产。
- 调用 咨询 接口,根据货币、交易发起终端类型、买家所在地区以及已签约的支付方式,获取当前交易支持的支付方式和标识链接。
以下图示展示了添加支付方式后的页面效果:
Web 预览
步骤 2:调用支付接口并获取支付推进链接
当买家选择由 Antom 提供的支付方式付款时,您需要收集支付请求ID、订单金额、支付方式、交易环境信息、订单描述、支付跳转页面链接以及接收支付结果通知的链接。然后,调用 支付(收银台)接口获取支付推进链接,并将买家重定向到支付推进链接指定的结账页面进行支付。
发起支付请求
Antom 提供了多种语言的服务器端接口库。以下代码以 Java 为例,您需要安装 Java 6 或更高版本。
安装接口库
您可以在 GitHub 上找到最新版本。
<dependency>
<groupId>com.alipay.global.sdk</groupId>
<artifactId>global-open-sdk-java</artifactId>
<version>2.0.36</version>
</dependency>
初始化请求实例
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);
}
创建支付请求
支付请求包含以下参数。
参数名称 | 是否必需 | 描述 |
productCode | 是 | 在此场景中,该字段设置为 |
paymentRequestId | 是 | 商家生成的专属 ID。 |
paymentAmount | 是 | 支付金额,以支付货币的最小单位设置。 |
paymentMethod | 是 | 支付方式枚举值。 |
paymentRedirectUrl | 是 | 商户端的支付结果页面,需要根据服务器返回的结果进行展示。 |
paymentNotifyUrl | 否 | 支付结果通知地址,可通过接口指定或在门户上设置固定值。 |
settlementStrategy | 否 | 支付的结算货币。如果您签署了多个结算货币,需要在接口中指定。 |
order | 是 | 包括订单金额、订单ID和订单描述的订单信息。 |
env | 是 | 买家发起交易的环境。 |
有关完整参数的更多信息,请参阅 支付(收银台)接口。
以下示例代码用于发起支付:
public static void pay() {
AlipayPayRequest alipayPayRequest = new AlipayPayRequest();
alipayPayRequest.setProductCode(ProductCodeType.CASHIER_PAYMENT);
// replace with your paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPayRequest.setPaymentRequestId(paymentRequestId);
// set amount
Amount amount = Amount.builder().currency("SGD").value("4200").build();
alipayPayRequest.setPaymentAmount(amount);
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("SHOPEEPAY_SG").build();
alipayPayRequest.setPaymentMethod(paymentMethod);
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// set order info
Order order = Order.builder().referenceOrderId(orderId)
.orderDescription("antom testing order").orderAmount(amount).buyer(buyer).build();
alipayPayRequest.setOrder(order);
// set env info
Env env = Env.builder().terminalType(TerminalType.WEB).build();
alipayPayRequest.setEnv(env);
// replace with your notify url
alipayPayRequest.setPaymentNotifyUrl("https://www.yourNotifyUrl.com");
// replace with your redirect url
alipayPayRequest.setPaymentRedirectUrl("https://www.yourMerchantWeb.com");
// do Payment
AlipayPayResponse alipayPayResponse = null;
try {
alipayPayResponse = CLIENT.execute(alipayPayRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// handle error condition
}
}
以下代码显示了请求报文的示例:
Web 示例代码
{
"env": {
"terminalType": "WEB"
},
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "SGD",
"value": "4200"
},
"orderDescription": "antom testing order",
"referenceOrderId": "referenceOrderId01"
},
"paymentAmount": {
"currency": "SGD",
"value": "4200"
},
"paymentMethod": {
"paymentMethodType": "SHOPEEPAY_SG"
},
"paymentNotifyUrl": "https://www.yourNotifyUrl.com",
"paymentRedirectUrl": "https://www.yourMerchantWeb.com",
"paymentRequestId": "paymentRequestId01",
"productCode": "CASHIER_PAYMENT"
}
常见问题
问:如何设置 terminalType ?
答:terminalType 的有效值为:
- 如果买家在PC端发起交易,需要将 terminalType 指定为
WEB
。- 如果买家在移动浏览器上发起交易,需要将 terminalType 指定为
WAP
。添加 osType 参数,并根据买家的手机填写相应的系统参数ANDROID
或IOS
。- 如果买家在应用内发起交易,需要将 terminalType 指定为
APP
。问:请求参数的值可以使用中文字符吗?
答:为了避免特定支付方式的兼容性问题,请求中的字段请勿使用中文字符。
问:如何设置接收支付通知的链接?
答:在 支付会话创建(收银台)接口中指定 paymentNotifyUrl 字段,以接收支付结果的异步通知(支付通知),或者在 Antom Dashboard 中配置接收链接。如果请求和 Antom Dashboard 中都指定了链接,请求中的值优先。
接收支付响应
以下为示例响应:
Web 示例代码
{
"normalUrl": "https://iexpfront-sea-global.alipay.com/payments/method/checkout/code.html?merchantId=1881CCJjl2BBCG6rka49PGy%2FoXzNOkE7yrezQj7guluiD8%3D&paymentRequestId=%2FoPiByS7aojWVwCaUlOAAlm4WlvaPbMSy%2FrDQP1AlMDEhodChPq8Oderh2GKY%2F9p&pass=lt%5E1&clientId=SANDBOX_XXXXXXXXXX",
"orderCodeForm": {
"codeDetails": [
{
"codeValue": "https://iexpfront-sea.alipay.com/showQrImage.htm?code=mmOd8ZsZBdQWrtZgFnUVXO2o5DwcbXxhYFq5Ydp1yv0%253D&size=M&pass=lt%5E1&sid=188",
"displayType": "MIDDLEIMAGE"
}
],
"expireTime": "2024-01-01T00:14:00+08:00"
},
"paymentActionForm": "{\"paymentActionFormType\":\"PaymentCodeForm\",\"paymentCodeExpireTime\":1720508173000,\"paymentCodeInfos\":[{\"paymentCodeDetails\":[{\"codeValue\":\"20240101123456789\",\"codeValueType\":\"QRCODE\",\"displayType\":\"IMAGE\"}],\"paymentCodeInfoType\":\"PAYMENT_CODE\"}]}",
"paymentAmount": {
"currency": "SGD",
"value": "4200"
},
"paymentCreateTime": "2024-01-01T00:00:00+08:00",
"paymentId": "20240101123456789XXXX",
"paymentRequestId": "paymentRequestId01",
"redirectActionForm": {
"method": "GET",
"redirectUrl": "https://iexpfront-sea-global.alipay.com/payments/method/checkout/code.html?merchantId=1881CCJjl2BBCG6rka49PGy%2FoXzNOkE7yrezQj7guluiD8%3D&paymentRequestId=%2FoPiByS7aojWVwCaUlOAAlm4WlvaPbMSy%2FrDQP1AlMDEhodChPq8Oderh2GKY%2F9p&pass=lt%5E1&clientId=SANDBOX_XXXXXXXXXX"
},
"result": {
"resultCode": "PAYMENT_IN_PROCESS",
"resultMessage": "payment in process",
"resultStatus": "U"
}
}
常见问题
问:什么是 normalUrl ?
答:对于 Web 或 WAP 交易,Antom 会返回 normalUrl,服务器端需要将其传递给客户端进行重定向。当您再次为同一订单发起支付时,需要获取新的 normalUrl 进行重定向。
问:什么是 paymentId ?
答:如果您需要存储相应的订单 ID 以备后续退款和对账,可以指定 paymentId。
重定向到支付方式的结账页面
Web 的链接类型
商家服务端传递 normalUrl 到客户端,然后在客户端页面重定向到 normalUrl。
常见问题
问:如何处理不同的支付体验?
答:您无需处理不同支付方式的不同体验。只需通过前端页面重定向到 normalUrl。不同的支付体验由 normalUrl 负责完成渲染和支付流程。
显示支付结果页面
您需要通过在 支付(收银台)接口中指定 paymentRedirectUrl 字段来提供一个 HTTPS 地址。该地址用于在商户端显示支付结果。
常见问题
问:支付结果页面显示什么内容?
答:无论是成功支付还是支付失败,支付方式端都会重定向到结果页面。
问:重定向到结果页面是否意味着支付成功了?
答:结果页面不能作为判断支付是否成功的依据:
- 买家成功支付后,由于网络或其他原因,可能不会被重定向到结果页面。
- 如果买家尚未完成支付,仍然存在可以重定向到结果页面的入口。
- Antom 不支持在 paymentRedirectUrl 字段中指定表示支付结果的信息。
步骤 3:获取支付结果
当买家完成支付或支付超时,您可以通过 Antom 异步通知或主动查询支付结果来获取相应的支付结果。
接收异步通知
完成支付或支付失败时, Antom 会通过 支付(收银台)接口中的参数 paymentNotifyUrl 指定的地址发送异步通知(支付通知)。如果每个支付的地址相同,您也可以在 Antom Dashboard中配置该地址。
以下是通知请求的示例代码:
{
"notifyType": "PAYMENT_RESULT",
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
},
"paymentRequestId": "paymentRequestId01",
"paymentId": "20240101123456789XXXX",
"paymentAmount": {
"value": "4200",
"currency": "SGD"
},
"paymentCreateTime": "2024-01-01T00:00:00+08:00",
"paymentTime": "2024-01-01T00:01:00+08:00"
}
如何验证通知的签名并做出响应,请参阅签名与验签。
以下是通知响应示例代码:
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "Success"
}
}
常见问题
问:何时会发送通知?
答:这取决于支付是否完成:
- 如果支付成功完成,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 :表示支付金额。
查询结果
调用 支付结果查询 接口,通过以下参数查询支付结果:
参数名称 | 是否必需? | 描述 |
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
}
}
获取响应代码
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "Success"
},
"paymentStatus": "SUCCESS",
"paymentRequestId": "paymentRequestId01",
"paymentId": "20240101123456789XXXX",
"paymentAmount": {
"value": "4200",
"currency": "SGD"
},
"paymentCreateTime": "2024-01-01T00:00:00+08:00",
"paymentTime": "2024-01-01T00:01:00+08:00",
"paymentMethodType": "SHOPEEPAY_SG"
}
常见问题
问:我应该多久调用一次 支付结果查询 接口?
答:以 2 秒的间隔持续调用 支付结果查询 接口,直到获取最终的支付结果或收到异步支付结果通知为止。
问:我在通知中需要使用哪些关键参数?
答:请注意以下关键参数:
- result:表示此 支付结果查询 接口调用的结果,需要根据 paymentStatus 来判断订单状态:
SUCCESS
和FAIL
表示最终结果。PROCESSING
表示处理中。
- paymentAmount:表示支付的金额。
最佳实践
遵循以下最佳实践以提高集成效率。
自定义支付超时时间
在收银台支付场景中,Antom 端的默认超时时间为 14 分钟。超时后,买家无法继续支付。 您可以通过 支付(收银台)接口中的 paymentExpireTime 参数指定超时时间。 超过指定时间后,买家将无法扫码或登录结账页面。
以下示例代码展示了如何在 支付(收银台)接口中指定 paymentExpireTime 参数:
Web 示例代码
{
"env": {
"terminalType": "WEB"
},
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "SGD",
"value": "4200"
},
"orderDescription": "antom testing order",
"referenceOrderId": "referenceOrderId01"
},
"paymentAmount": {
"currency": "SGD",
"value": "4200"
},
"paymentExpiryTime": "2024-01-01T00:30:00+08:00",
"paymentMethod": {
"paymentMethodType": "SHOPEEPAY_SG"
},
"paymentNotifyUrl": "https://www.yourNotifyUrl.com",
"paymentRedirectUrl": "https://www.yourMerchantWeb.com",
"paymentRequestId": "paymentRequestId01",
"productCode": "CASHIER_PAYMENT"
}
如果您指定了 paymentExpireTime ,买家可以支付的有效时间将变为 paymentExpireTime 中的时间。
如果买家在此时间后付款,会有以下两种可能:
- 买家无法完成支付。
- 买家付款后会立即收到退款。
获取支付推进链接
Antom 提供了直接连接到多种支付方式的功能。在某些情况下,支付方式的订单接口处理延迟可能无法及时收到响应。因此,买家可能不会被重定向到支付推进链接,这可能会降低支付成功率并影响用户体验。
建议将接口超时时间设置为 10 秒,以提高响应成功率。若支付调用超时,建议重新发起原始请求以获取支付推进链接。
优化支付体验
对于通过 PC 发起的交易,某些支付方式允许买家通过扫描二维码或输入密码完成购买,无需重定向。当买家选择这种支付方式时,接口响应中的相应代码会直接在您的页面上渲染。这使得可以快速向买家展示二维码或密码,简化支付流程,提升用户体验。
Antom 返回的二维码不会自动刷新。显示二维码时,添加接口响应中的 expireTime 以显示过期时间。显示密码时,密码的复制功能是启用的 ,让买家可以方便地将密码粘贴到支付应用中。
跳转到商户结果页面
- 不是所有启动应用的支付方式在完成时都会重定向到商户指定的结果页面。某些支付方式不支持,例如 Kakaopay(KakaoTalk)。
- 如果买家安装了多个浏览器,支付后重定向到 HTTPS 结果页面将在他们的默认浏览器中进行。然而,此限制不适用于特定协议的链接,这些链接不受买家选择的浏览器影响。
商户结果页面处理逻辑建议
- 处理重定向问题
当买家成功完成支付,但在跳转到您指定的 paymentRedirectUrl 时遇到问题,无论是由于网络问题还是支付方式的限制,请注意以下两点:
- 不能将客户端重定向作为判断支付成功的依据。
- 如果支付方法页面的 paymentRedirectUrl 未能重定向到商户页面,买家可以手动点击原始商户页面。为了避免买家误以为订单未支付而再次尝试支付,建议在原始商户页面上实现一个弹出窗口,用于查询交易结果。当买家点击此弹出窗口时,应显示交易结果,防止重复支付尝试。
- 重定向后触发订单结果查询
如果在调用 支付结果查询 接口后,商户端弹出,建议处理以下不同的结果:
- 支付成功:支付成功后,页面将显示与发货相关的内容。
- 支付失败:表明支付失败,并提供重试支付的指导,以帮助订单完成。
- 支付处理中:显示加载效果,并在 3-5 秒内暂停,然后再次查询服务器以获取支付结果。如果结果仍然不确定(既不是成功也不是失败),建议显示“订单处理中”或“通过订单管理门户查看最终结果”。避免将延迟归因于“网络处理”。
支付失败重试
订单的支付尝试失败,且买家可以为同一订单重试支付时,我们建议遵循以下集成流程以实现无缝体验:
- 在支付请求中,将 referenceOrderId 设置为订单 ID,将 paymentRequestId 设置为支付订单 ID。
- 如果需要对同一订单重试支付,首先检查订单状态。如果支付已经成功,向买家显示“已完成支付”。如果没有,再次调用 支付(收银台)接口以获取新的 normalUrl 进行重定向。虽然 referenceOrderId 保持不变,因为它代表相同的订单,但后续支付尝试时必须更新 paymentRequestId 。
- 确保每个商户订单只与一个成功的支付相关联。如果检测到单个订单有多个成功的支付,调用 取消支付 接口来为买家发起退款。
- 对于不支持退款的支付方式,建议在发起新支付之前取消原始支付。
获取支付结果
为了确保稳定地获取支付结果,避免出现买家完成支付但您未收到支付结果的情况,建议您在以下阶段检查支付结果:
- 当显示商户支付结果页面时。
- 在发货给买家之前。
- 当您收到 Antom 对账文件时。
开放支付方式链接
支付方式特性 | 链接类型 | 解决方案 | 优缺点 |
仅支持应用内结账 | applinkUrl | 重定向到支付方式应用结账: iOS 调用 openUrl 方法,Android 调用 startActivity 方法。 | 优点:
|
normalUrl | 跳转到支付方式应用结账: iOS 调用 openUrl 方法,Android 调用 startActivity 方法。 | 优点:
缺点:
| |
schemeUrl | 跳转到支付方式应用结账: iOS 调用 openUrl 方法,Android 调用 startActivity 方法。 | 优点:
缺点:
| |
仅支持移动网站结账 | normalUrl | 在 WebView 中打开结账链接。 | 优点:
|
支持应用和移动网站 结账 | applinkUrl | iOS 调用 openUrl 方法,Android 调用 startActivity 方法。 | 优点:
缺点:
|
normalUrl | 在 WebView 中打开结账链接。 | 优点:
缺点:
| |
schemeUrl | iOS 调用 openUrl 方法,Android 调用 startActivity 方法。 | 优点:
缺点:
|
处理 Android 中的消歧提示框
更多信息请参阅谷歌文档。
使用 WebView 加载订单页面
为了提供良好的用户体验,您可以在客户端使用 WebView 加载订单页面。点击订单后,可以直接重定向到支持支付方式的移动应用来完成支付。您可以参考 JavaScript 代码与移动客户端代码的绑定来实现这种交互体验。