PAYATHON 2026

自研终端设备如何接入支付宝支付API?

支付老李

明确结论

支付宝支持自研终端收款,但一般没有“终端设备接入后直接扣款”的通用 API。

终端应作为商户的收银设备,由商户服务端接入支付宝开放平台。选择哪种方案,取决于终端与用户的交互方式:

  • 终端可以显示二维码:使用“当面付”的扫码支付,由服务端调用 alipay.trade.precreate 生成支付二维码,用户使用支付宝扫码付款。
  • 终端可以扫描用户的支付宝付款码:使用“当面付”的条码支付,由服务端调用 alipay.trade.pay 收款。这种方案对商户资质、产品签约、设备安全和风控有更高要求。
  • 终端没有屏幕或扫码器,希望通过 NFC、实体卡、学生卡账户或设备身份直接扣款:普通开放 API 一般无法实现,需要向支付宝或具有相关资质的支付服务商申请行业合作方案。
  • 如果终端可以运行支付宝小程序或跳转到支付宝客户端,可以评估小程序支付、手机网站支付等产品,但这不属于独立硬件直接扣款。

商户最终能使用哪些产品和接口,以支付宝开放平台中该商户账号实际可以签约的能力为准。

为什么不能由终端直接调用支付 API

支付接口涉及商户私钥、应用证书、签名、订单校验和异步通知验签。将这些能力直接放进终端,会产生以下风险:

  • 设备可能被拆机、调试或提取固件,造成商户私钥泄露。
  • 订单金额、商户订单号和支付状态可能被篡改。
  • 网络中断后,终端可能将“接口超时”误判为“支付失败”。
  • 用户付款码是敏感支付凭证,不应保存、写入日志或重复使用。
  • 学生卡等场景还涉及未成年人、账户授权和消费限额,不能只凭设备编号发起扣款。

建议采用以下架构:

用户支付宝
    ↕
自研终端 ←→ 商户业务服务端 ←→ 支付宝开放平台
                 ↕
             订单数据库

终端负责采集支付信息、展示二维码和显示支付结果。签名、验签、创建及查询订单、退款和处理异步通知等操作,都应放在可信服务端完成。

方案一:终端展示二维码,用户扫码付款

这种方式通常更适合自研终端落地。

基本流程如下:

  1. 商户在支付宝开放平台创建应用。
  2. 根据平台页面提供的能力,申请并签约当面付产品。
  3. 配置应用密钥或证书以及支付宝公钥。
  4. 终端将商品、金额和设备编号提交给商户服务端。
  5. 服务端创建本地订单,并调用 alipay.trade.precreate。
  6. 服务端将返回的 qr_code 发给终端。
  7. 终端显示二维码,用户使用支付宝扫码付款。
  8. 服务端接收支付宝异步通知,并在必要时主动调用 alipay.trade.query 确认状态。
  9. 服务端将最终支付结果同步给终端。

服务端请求示例:

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 发送通知后,服务端至少需要完成以下检查:

  1. 使用支付宝公钥或证书验证签名。
  2. 检查 app_id 是否属于当前应用。
  3. 检查 out_trade_no 是否存在。
  4. 核对金额和收款方信息是否与本地订单一致。
  5. 根据 trade_status 幂等更新订单。
  6. 处理成功后,按支付宝要求返回成功响应。

示意代码如下:

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。应准备业务方案、设备形态、交易流程、预计规模、收款主体和风控设计,再通过支付宝开放平台的能力咨询入口或支付宝服务商渠道,确认是否有适用的行业合作产品。

备注:内容仅供参考。