超市收银系统调用支付宝API扫描付款码收款
明确结论
超市收银台扫描顾客的支付宝付款码,属于支付宝「当面付」中的条码支付场景,使用的接口是:
alipay.trade.pay
请求时需要传入收银设备扫描到的付款码,并设置:
scene=bar_code
auth_code=扫描得到的付款码
商户服务端可以通过支付宝开放平台提供的 Java、PHP、C#、Python 等服务端 SDK 调用该接口。不要将付款码提交到浏览器,也不要让收银客户端携带商户私钥直接请求支付宝。支付请求应由商户服务端发起。
接口文档、SDK 和示例可以在支付宝开放平台查找:
- 开放平台:
https://open.alipay.com/ - 在文档中心搜索:
alipay.trade.pay - 在产品中心搜索:
当面付 - 在开发工具或资源中心搜索:
服务端 SDK、当面付 Demo
开放平台的栏目和下载入口可能调整。如果链接结构发生变化,直接搜索这些关键词即可。
为什么使用 alipay.trade.pay
支付流程如下:
- 顾客打开支付宝付款码。
- 收银员使用扫码枪或扫码设备读取付款码。
- 收银系统将付款码、订单号和金额发送到商户服务端。
- 商户服务端调用
alipay.trade.pay。 - 支付宝完成扣款并返回交易结果。
这种方式是商户主动扫描消费者付款码的「被扫支付」。用户扫描商户二维码后自行付款属于「扫码支付」,通常会用到预创建交易等接口,两种流程不能混用。
接入步骤
1. 创建并配置支付宝开放平台应用
先在支付宝开放平台创建应用,再根据实际签约产品开通当面付能力。通常需要准备以下配置:
- 应用
app_id - 支付宝网关地址
- 商户应用私钥
- 应用公钥或支付宝公钥证书
- 支付宝公钥或支付宝公钥证书
- 签名算法,一般为
RSA2
普通公钥模式和证书模式的 SDK 初始化方式不同,具体使用哪一种,应以应用后台的当前配置为准。
2. 安装服务端 SDK
以 Java 为例,可以从支付宝开放平台下载当前推荐版本的服务端 SDK,并按对应文档引入依赖。SDK 会持续更新,在没有核对官方仓库或开放平台说明前,不要直接照搬固定版本号。
3. 扫描并提交付款码
扫码枪通常会模拟键盘输入,也可能通过串口或厂商 SDK 返回付款码。收银客户端取得付款码后,只将其提交给受控的商户服务端。
付款码是敏感支付数据,不要写入普通业务日志,也不要在错误信息中完整输出。
4. 服务端调用支付接口
下面是普通公钥模式下的 Java 调用结构示例。所有配置项都应从安全配置中心读取,不要直接写入源代码。
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.response.AlipayTradePayResponse;
public class AlipayBarcodePaymentService {
private final AlipayClient alipayClient;
public AlipayBarcodePaymentService(
String gatewayUrl,
String appId,
String merchantPrivateKey,
String alipayPublicKey) {
this.alipayClient = new DefaultAlipayClient(
gatewayUrl,
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
}
public AlipayTradePayResponse pay(
String outTradeNo,
String authCode,
String totalAmount,
String subject) throws Exception {
AlipayTradePayModel model = new AlipayTradePayModel();
model.setOutTradeNo(outTradeNo);
model.setScene("bar_code");
model.setAuthCode(authCode);
model.setTotalAmount(totalAmount);
model.setSubject(subject);
AlipayTradePayRequest request = new AlipayTradePayRequest();
request.setBizModel(model);
return alipayClient.execute(request);
}
}
调用示例:
AlipayTradePayResponse response = paymentService.pay(
"POS202609080001",
scannedAuthCode,
"38.50",
"超市购物"
);
if (response.isSuccess()) {
System.out.println("支付成功,支付宝交易号:" + response.getTradeNo());
} else {
System.out.println(
"支付未成功,code=" + response.getCode()
+ ", subCode=" + response.getSubCode()
+ ", subMsg=" + response.getSubMsg()
);
}
这段示例只展示了主要调用方式。生产环境不能仅根据 isSuccess() 判断并覆盖所有支付状态,还要结合接口返回码、业务子码和交易查询结果进行处理。
支付结果处理
条码支付可能立即成功,也可能因为用户需要输入密码、网络超时或渠道仍在处理中,暂时无法得到最终结果。收银系统至少要处理以下情况:
- 明确支付成功:保存支付宝交易号并完成订单。
- 明确支付失败:向收银员显示容易理解的失败原因。
- 支付处理中:在短时间内轮询交易状态。
- 请求超时或结果未知:调用交易查询接口确认。不能直接认定支付失败后再次扣款。
- 最终无法确认:按照官方流程撤销交易,并保留人工核对入口。
常用的配套接口包括:
alipay.trade.query
alipay.trade.cancel
alipay.trade.refund
查询接口用于确认交易状态,撤销接口用于处理结果未知或异常的交易,退款接口用于退回已经支付成功的交易。具体的调用时机、重试间隔和撤销策略,应以支付宝开放平台当前的当面付接入文档为准。
订单号与重复请求
out_trade_no 是商户订单号,必须在商户系统内保持唯一,并支持幂等处理。网络超时后不要生成新的订单号再次扣款,否则可能产生两笔交易。
建议按以下流程处理:
- 首次支付前生成唯一的
out_trade_no。 - 调用超时后,使用同一个订单号查询交易。
- 如果状态仍不明确,按官方建议继续查询或撤销。
- 确认原交易不存在或已经关闭后,才能重新发起支付。
金额应使用十进制字符串或可靠的十进制定点类型处理,例如 Java 的 BigDecimal,不要使用 double 直接计算金额。
如何找到接口文档和 Demo
进入支付宝开放平台后,可以搜索以下关键词:
当面付 条码支付
alipay.trade.pay
服务端 SDK
当面付 Demo
沙箱环境
阅读接口文档时,需要重点确认:
- 公共请求参数和签名方式
biz_content业务参数scene与auth_code的要求- 返回码和业务错误码
- 支付处理中状态的处理方式
- 查询、撤销和退款接口
- 普通公钥与证书模式的初始化方法
如果官方 Demo 与当前 SDK 的类名或初始化方法不一致,应以所下载 SDK 对应版本的官方文档为准,不要混用不同年代的示例代码。
注意事项
- 付款码通常有时效性,只能用于当前支付,不应保存或重复使用。
- 商户私钥必须保存在服务端,并通过密钥管理或安全配置系统加载。
- 日志中的
auth_code、私钥、签名内容及其他敏感数据必须脱敏。 - 收银客户端和服务端之间必须使用 HTTPS,同时做好身份认证和防重放处理。
- 支付是否成功,应以支付宝接口返回并经查询确认的交易状态为准,不能只看前端提示。
- 正式上线前,应测试支付成功、余额不足、用户输密、付款码失效、网络超时、重复请求、撤销和退款等场景。
- 沙箱能力、付款码获取方式和可测试范围可能与生产环境不同,应以开放平台当前说明为准。
备注:内容仅供参考。
