自研终端设备如何接入支付宝支付API?
明确结论
支付宝支持自研终端收款,但一般没有“终端设备接入后直接扣款”的通用 API。
终端应作为商户的收银设备,由商户服务端接入支付宝开放平台。选择哪种方案,取决于终端与用户的交互方式:
- 终端可以显示二维码:使用“当面付”的扫码支付,由服务端调用
alipay.trade.precreate生成支付二维码,用户使用支付宝扫码付款。 - 终端可以扫描用户的支付宝付款码:使用“当面付”的条码支付,由服务端调用
alipay.trade.pay收款。这种方案对商户资质、产品签约、设备安全和风控有更高要求。 - 终端没有屏幕或扫码器,希望通过 NFC、实体卡、学生卡账户或设备身份直接扣款:普通开放 API 一般无法实现,需要向支付宝或具有相关资质的支付服务商申请行业合作方案。
- 如果终端可以运行支付宝小程序或跳转到支付宝客户端,可以评估小程序支付、手机网站支付等产品,但这不属于独立硬件直接扣款。
商户最终能使用哪些产品和接口,以支付宝开放平台中该商户账号实际可以签约的能力为准。
为什么不能由终端直接调用支付 API
支付接口涉及商户私钥、应用证书、签名、订单校验和异步通知验签。将这些能力直接放进终端,会产生以下风险:
- 设备可能被拆机、调试或提取固件,造成商户私钥泄露。
- 订单金额、商户订单号和支付状态可能被篡改。
- 网络中断后,终端可能将“接口超时”误判为“支付失败”。
- 用户付款码是敏感支付凭证,不应保存、写入日志或重复使用。
- 学生卡等场景还涉及未成年人、账户授权和消费限额,不能只凭设备编号发起扣款。
建议采用以下架构:
用户支付宝
↕
自研终端 ←→ 商户业务服务端 ←→ 支付宝开放平台
↕
订单数据库
终端负责采集支付信息、展示二维码和显示支付结果。签名、验签、创建及查询订单、退款和处理异步通知等操作,都应放在可信服务端完成。
方案一:终端展示二维码,用户扫码付款
这种方式通常更适合自研终端落地。
基本流程如下:
- 商户在支付宝开放平台创建应用。
- 根据平台页面提供的能力,申请并签约当面付产品。
- 配置应用密钥或证书以及支付宝公钥。
- 终端将商品、金额和设备编号提交给商户服务端。
- 服务端创建本地订单,并调用
alipay.trade.precreate。 - 服务端将返回的
qr_code发给终端。 - 终端显示二维码,用户使用支付宝扫码付款。
- 服务端接收支付宝异步通知,并在必要时主动调用
alipay.trade.query确认状态。 - 服务端将最终支付结果同步给终端。
服务端请求示例:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
request.setNotifyUrl("https://merchant.example.com/alipay/notify");
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
model.setOutTradeNo("ORDER_20260908_000001");
model.setSubject("终端消费");
model.setTotalAmount("10.00");
request.setBizModel(model);
AlipayTradePrecreateResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
String qrCode = response.getQrCode();
// 将 qrCode 返回给终端,由终端生成并展示二维码
} else {
// 记录 code、subCode、subMsg,按错误类型处理
}
这段示例只展示核心调用方式。SDK 依赖、密钥模式和请求模型,应以支付宝开放平台当前文档及所选 SDK 为准。
方案二:终端扫描用户付款码
终端配有扫码器时,可以读取用户主动出示的支付宝付款码,再将付款码发送给商户服务端。服务端通过 alipay.trade.pay 发起条码支付。
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradePayRequest request = new AlipayTradePayRequest();
AlipayTradePayModel model = new AlipayTradePayModel();
model.setOutTradeNo("ORDER_20260908_000002");
model.setSubject("终端消费");
model.setTotalAmount("10.00");
model.setAuthCode(userPresentedAuthCode);
model.setScene("bar_code");
request.setBizModel(model);
AlipayTradePayResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
// 不应只根据 HTTP 状态判断,应检查支付宝业务响应和订单状态
} else {
// 对等待用户确认、处理中、超时等情况执行订单查询
}
付款码必须由用户在本次消费时主动出示。终端和服务端都不应长期保存 auth_code,也不能使用历史付款码再次扣款。
部分交易可能处于等待用户确认或处理中,不能将一次接口失败直接视为未支付。如果请求超时或结果不明确,应使用原商户订单号调用 alipay.trade.query 查询。确认最终状态后,再决定是否重试或关闭订单。
服务端需要实现的核心接口
实际系统除支付接口外,至少还应具备以下能力:
alipay.trade.precreate:生成扫码支付二维码。alipay.trade.pay:处理用户付款码支付。alipay.trade.query:查询订单的最终支付状态。alipay.trade.refund:按原订单发起退款。- 异步通知接收接口:验签后更新本地订单状态。
每种方案不一定需要同时使用以上全部接口。终端展示二维码时,通常以 alipay.trade.precreate 为主;扫描用户付款码时,通常以 alipay.trade.pay 为主。
异步通知必须验签
支付宝向 notify_url 发送通知后,服务端至少需要完成以下检查:
- 使用支付宝公钥或证书验证签名。
- 检查
app_id是否属于当前应用。 - 检查
out_trade_no是否存在。 - 核对金额和收款方信息是否与本地订单一致。
- 根据
trade_status幂等更新订单。 - 处理成功后,按支付宝要求返回成功响应。
示意代码如下:
Map<String, String> params = extractRequestParameters(httpRequest);
boolean valid = AlipaySignature.rsaCheckV1(
params,
alipayPublicKey,
"UTF-8",
"RSA2"
);
if (!valid) {
throw new SecurityException("Invalid Alipay signature");
}
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
// 查询本地订单并校验 app_id、订单金额和收款方信息。
// 使用事务或唯一约束保证重复通知不会重复记账。
普通公钥模式、证书模式和不同 SDK 版本使用的验签方法可能不同,应采用当前官方文档对应的实现。
推荐的接入步骤
1. 明确交易形态
先确认设备具备哪些交互能力:
- 有屏幕:优先考虑展示动态二维码。
- 有扫码器:可以评估扫描用户付款码。
- 只有 NFC、蓝牙或自定义学生卡:需要申请行业合作方案,不能直接套用扫码支付接口。
- 设备绑定家长账户并自动扣款:需要单独评估签约代扣等产品,不能用普通支付接口模拟自动扣款。
2. 准备商户和应用
使用真实经营主体完成支付宝商家认证,并在支付宝开放平台创建应用。根据业务类型申请相应产品,按要求提交经营类目、应用场景和设备说明。
如果软件服务商需要为多所学校或多个商户提供系统,还应评估 ISV 服务商模式,避免所有终端共用一个与实际收款主体不匹配的商户账号。
3. 配置安全凭据
以下凭据应配置在可信服务端:
app_id- 商户私钥
- 支付宝公钥或应用证书
- 支付宝公钥证书
- 支付宝根证书
- 异步通知地址
需要配置哪些证书,取决于所选签名模式。私钥不得写入终端固件、移动应用安装包、前端 JavaScript 或公开代码仓库。
4. 先完成沙箱联调
沙箱可以验证请求签名、订单创建、支付状态流转、异步通知和退款逻辑,但它支持的范围可能与生产环境不同。正式上线前,仍需使用生产应用完成小额且可退款的全链路验证。
5. 建立设备与订单管理
每台终端都应具有不可伪造的设备身份。终端访问业务服务端时需要进行身份认证,并在订单中记录:
- 商户订单号
- 设备编号
- 门店编号
- 商品和金额
- 支付宝交易号
- 创建时间和支付时间
- 当前交易状态
服务端不能无条件信任设备上报的金额。对于固定商品或套餐,应由服务端根据商品编号计算价格。
特殊终端场景的注意事项
不要把设备身份当成支付授权
设备编号、学生卡号、NFC UID 或二维码标签只能用于识别设备或业务账户,不能证明用户已经授权支付宝付款。支付授权必须通过支付宝支持的付款流程完成。
离线状态不能直接判定支付成功
终端断网、接口超时或通知延迟时,交易可能已经成功。系统应将订单标记为“支付结果未知”或“处理中”,并在网络恢复后调用 alipay.trade.query 对账。不要立即使用同一个业务订单重复扣款。
商户订单号必须唯一
out_trade_no 应由服务端生成,并在商户应用范围内保持唯一。重试同一订单时,应继续使用原订单号查询或处理,避免生成新订单号后发生重复支付。
二维码应设置合理有效期
动态支付二维码应绑定具体订单,并在支付完成、订单关闭或超时后立即失效。不要让设备长期展示可被拍照转发的固定收款码,以此替代订单支付流程。
未成年人场景需要单独评估
智能学生卡通常涉及未成年人消费。除了支付接口,还要考虑监护人授权、消费限额、退款、账单展示、个人信息保护和学校场景的合规要求。这些问题无法只靠普通支付 API 解决。
如何选择
设备有屏幕时,建议先使用 alipay.trade.precreate 展示动态二维码。这种方案的接入方式和安全边界相对清晰。
如果终端必须扫描用户付款码,应先申请相应的当面付能力。确认硬件、安全和风控要求后,再使用 alipay.trade.pay。
如果目标是“刷学生卡、碰一碰或识别设备后直接从支付宝账户扣款”,不要自行拼接普通开放 API。应准备业务方案、设备形态、交易流程、预计规模、收款主体和风控设计,再通过支付宝开放平台的能力咨询入口或支付宝服务商渠道,确认是否有适用的行业合作产品。
备注:内容仅供参考。
