支付宝NFC碰一碰设备如何接入收款功能?
结论
支付宝”碰一下”收款通常不是通过独立、公开的 NFC 支付 API 实现的。NFC 设备主要用于识别设备或唤起支付宝,下单、支付和回调仍由支付宝现有的支付产品完成。
如果要接入支付宝官方的”碰一下支付”设备,需要先确认商户或服务商是否已经开通相应产品,再通过支付宝服务商渠道申请设备、接入文档和 SDK。公开平台中找不到”碰一下收款 API”,不等于可以使用普通 NFC 接口自行模拟整套支付流程。
为什么找不到对应 API
“碰一下”可能涉及两类不同的方案:
-
普通 NFC 标签或自有 NFC 设备
NFC 中只保存链接、设备编号或门店信息。手机碰触后进入支付宝小程序、H5 页面或其他业务入口,再由页面调用常规支付能力。
-
支付宝官方”碰一下支付”设备
这是支付宝支付产品与认证硬件结合的方案。设备开通、绑定、密钥、交易协议和风控通常由支付宝或授权服务商提供,未必会作为通用开放 API 向所有开发者开放。
NFC 本身不是支付接口。它解决的是”用户碰了哪台设备、进入哪个场景”,支付 API 负责创建订单、确认支付、发送异步通知和处理退款。
推荐的接入方式
方案一:接入支付宝官方”碰一下支付”
适用于已经采购或准备采购支付宝官方设备、授权服务商设备的商户。
基本流程如下:
- 使用企业支付宝账号完成商户签约。
- 联系支付宝服务商或设备供应商,确认设备是否支持”碰一下支付”。
- 申请相应的产品权限和测试环境。
- 获取设备接入文档、SDK、设备编号和密钥配置方式。
- 在服务端接入订单创建、支付结果通知、查询和退款。
- 完成设备绑定、门店绑定和联调验收。
仅凭 NFC 芯片型号或设备序列号,无法完成这类设备的接入。硬件支持 NFC,也不代表它具备支付宝官方支付受理能力。
方案二:通过 NFC 唤起支付宝小程序,再调用常规支付
如果使用的是普通 NFC 标签或自研 NFC 终端,可以将 NFC 作为业务入口。典型流程如下:
用户碰触 NFC
↓
读取设备入口或设备标识
↓
进入支付宝小程序
↓
小程序向商户服务端请求下单
↓
服务端调用 alipay.trade.create
↓
返回 trade_no
↓
小程序调用 my.tradePay
↓
服务端接收支付宝异步通知
这种方式需要验证目标手机和操作系统能否通过 NFC 稳定进入指定的支付宝页面。如果在 NFC 标签中直接写入私有 Scheme,可能会受到操作系统、支付宝客户端版本和安全策略的限制,因此上线前必须使用真实设备测试。
服务端创建订单示例
下面以支付宝小程序支付的常见流程为例。具体参数应以商户已签约产品的当前官方文档为准。
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
request.setNotifyUrl("https://merchant.example.com/alipay/notify");
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", "ORDER_202609090001");
bizContent.put("total_amount", "0.01");
bizContent.put("subject", "门店消费");
bizContent.put("buyer_id", buyerId);
request.setBizContent(bizContent.toJSONString());
AlipayTradeCreateResponse response = alipayClient.execute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
response.getCode() + ": " + response.getSubMsg()
);
}
String tradeNo = response.getTradeNo();
buyer_id 的获取方式取决于小程序授权流程和已经开通的产品能力,客户端不能自行伪造。
小程序发起支付示例
服务端创建订单并返回 trade_no 后,小程序端可以调用支付能力:
my.tradePay({
tradeNO: tradeNo,
success: (result) => {
console.log('支付调用完成', result);
queryOrderStatus();
},
fail: (error) => {
console.error('支付调用失败', error);
}
});
客户端返回成功,只能说明支付组件调用完成,不能作为最终到账依据。页面显示”支付成功”前,建议先向商户服务端查询订单状态。
异步通知处理
支付结果应以支付宝服务端的异步通知或主动查询结果为准。处理通知时至少需要:
- 验证支付宝签名。
- 核对
app_id、商户订单号和交易金额。 - 判断通知中的交易状态。
- 使用数据库事务更新订单。
- 确保重复通知不会导致重复记账或重复发货。
- 按接口要求返回确认响应。
示意代码如下:
Map<String, String> params = getNotifyParams(request);
boolean valid = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2"
);
if (!valid) {
response.getWriter().write("failure");
return;
}
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
String appId = params.get("app_id");
verifyOrder(outTradeNo, totalAmount, appId);
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
markOrderPaidIdempotently(outTradeNo, params.get("trade_no"));
}
response.getWriter().write("success");
这段代码只展示处理结构。getNotifyParams、verifyOrder 和 markOrderPaidIdempotently 需要结合实际使用的框架和订单系统实现。
NFC 设备应传递什么信息
自有 NFC 设备只适合传递不敏感的场景信息,例如:
device_id
store_id
terminal_id
scene_token
不要在 NFC 标签中存放商户私钥、接口密钥、固定付款金额或可重复使用的授权凭证。普通 NFC 标签可能被读取、复制或替换,因此服务端还需要:
- 校验设备是否已绑定商户和门店;
- 使用短时有效且只能使用一次的
scene_token; - 防止同一令牌重复下单;
- 在服务端校验金额、商品和订单状态;
- 限制异常频率、跨门店使用和重复碰触。
如果 NFC 标签只能保存静态内容,可以写入设备入口和随机设备标识,但订单金额必须由可信的服务端生成,不能直接采用 NFC 内容中的金额。
容易混淆的接口
alipay.trade.precreate 通常用于生成当面付二维码,alipay.trade.create 可以用于创建支付宝交易。两者都是支付交易接口,不是”NFC 碰一下接口”。
NFC 能否直接拉起付款、如何获取用户身份、设备是否需要认证,以及能否实现接近官方”碰一下支付”的体验,取决于已签约产品、终端类型和支付宝提供的接入能力,无法仅靠替换支付接口实现。
接入前需要确认的事项
正式开发前,应先向设备供应商或支付宝服务商确认:
- 设备是否为支付宝认证或授权设备;
- 产品名称是”碰一下支付”,还是普通 NFC 唤起;
- 商户是否已经取得相应的产品权限;
- 是否提供设备 SDK、测试环境和联调账号;
- 订单由设备、支付宝小程序还是商户服务端创建;
- 是否支持退款、撤销、订单查询和对账;
- NFC 唤起方式支持哪些手机系统;
- 设备丢失、被复制或解绑后如何处理。
如果供应商只能提供 NFC 硬件,无法提供支付宝产品权限、SDK 或正式接入文档,那么该设备通常只能作为小程序或网页的入口,不能直接实现支付宝官方的”碰一下收款”。
备注:内容仅供参考。
