支付宝当面付如何通过三方应用授权收款到同主体账号
结论
可以采用三方应用授权模式,由商户账号 B 收款。
调用 alipay.trade.create 时:
app_id使用商户账号 A 创建的三方应用 APPID;- 请求使用三方应用私钥签名;
- 验签使用该三方应用配置对应的支付宝公钥;
app_auth_token必须是商户账号 B 授权后生成的有效令牌;- 商户账号 B 需要签约并开通当面付产品权限;
- 三方应用需要接入当面付功能包,并取得调用接口所需的权限。
满足这些条件后,三方应用只是代商户 B 发起交易。交易归属、收款以及后续的退款、查询、对账等业务,主体都是商户 B,而不是创建三方应用的商户账号 A。
小程序应用 A 取得服务端返回的支付宝交易号后,可以调用 my.tradePay 唤起支付。不过,小程序能否支付这笔交易,仍取决于支付宝开放平台对应用关联关系、支付场景和当前产品权限的校验。即使两个账号属于同一主体,也不能绕过产品或应用权限限制。
实现流程
1. 商户账号 A 创建三方应用
在支付宝开放平台创建三方应用,配置应用密钥,并为应用添加当面付相关功能包。
服务端需要保存:
- 三方应用 APPID;
- 三方应用私钥;
- 三方应用对应的支付宝公钥;
- 支付宝网关地址;
- 商户授权后获得的
app_auth_token。
三方应用私钥只能保存在服务端,不能放进小程序前端。
2. 商户账号 B 完成产品签约和应用授权
商户账号 B 应先确认已经签约当面付,并且账号状态、结算能力和接口权限均正常。
随后,商户 B 通过三方应用提供的授权链接完成授权。授权成功后,三方应用服务端使用授权码换取:
app_auth_token;app_refresh_token;- 授权商户身份信息;
- 令牌有效期等信息。
创建交易时使用的是 app_auth_token,不是授权过程中取得的一次性授权码。
3. 服务端以商户 B 的身份创建交易
各项请求参数和配置应按下表使用:
| 参数或配置 | 应使用的值 |
|---|---|
app_id | 商户账号 A 创建的三方应用 APPID |
| 请求签名 | 三方应用私钥 |
| 验签公钥 | 三方应用配置对应的支付宝公钥 |
app_auth_token | 商户账号 B 授权后生成的令牌 |
| 当面付签约主体 | 商户账号 B |
out_trade_no | 三方应用为商户 B 生成的唯一订单号 |
app_auth_token 决定了三方应用代哪个商户调用接口。如果不传这个参数,请求通常会按三方应用自身的业务身份处理,无法达到代商户 B 收款的目的。
下面是一个 Java SDK 示例。支付宝 SDK 版本不同,具体类名和构造方式可能略有差异:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
ISV_APP_ID,
ISV_APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", "B202609090001");
bizContent.put("total_amount", "0.01");
bizContent.put("subject", "门店订单");
// alipay.trade.create 通常需要提供付款用户标识。
// 实际使用 buyer_id、buyer_open_id 或其他字段,应以当前接口文档和应用模式为准。
bizContent.put("buyer_id", buyerId);
request.setBizContent(bizContent.toJSONString());
// 必须使用商户账号 B 授权产生的 app_auth_token
AlipayTradeCreateResponse response =
alipayClient.execute(request, null, merchantBAppAuthToken);
if (!response.isSuccess()) {
throw new IllegalStateException(
"创建交易失败:" + response.getCode()
+ " / " + response.getSubCode()
+ " / " + response.getSubMsg()
);
}
String tradeNo = response.getTradeNo();
部分 SDK 也支持通过请求对象或通用请求参数设置 app_auth_token。无论使用哪种写法,都要确认它最终出现在支付宝开放平台请求的公共参数中,不能放进 biz_content。
4. 小程序使用 tradeNO 唤起支付
服务端成功创建交易后,只向小程序返回支付宝交易号和必要的业务状态,不要返回私钥或 app_auth_token。
my.tradePay({
tradeNO: tradeNo,
success: (result) => {
console.log("支付调用完成", result);
// 前端结果仅用于页面展示。
// 最终支付状态应由服务端主动查询或异步通知确认。
},
fail: (error) => {
console.error("支付调用失败", error);
}
});
参数名应为 tradeNO,其值来自 alipay.trade.create 返回的支付宝交易号 trade_no。
如何确认实际收款方
不能只根据小程序所属账号判断收款方。应由服务端查询交易,并核对授权商户和交易归属。
查询时仍然需要使用:
- 三方应用 APPID;
- 三方应用私钥;
- 商户 B 的
app_auth_token; - 创建交易时的
out_trade_no或支付宝trade_no。
退款、撤销、关闭交易和账单处理也需要继续携带商户 B 对应的 app_auth_token。如果查询或退款时误用了其他商户的令牌,可能会出现“交易不存在”“无权限操作该交易”等错误。
注意事项
app_auth_token 必须与商户 B 对应
不能使用商户 A 的令牌,也不能把 app_refresh_token 当作调用令牌。建议在数据库中建立清晰的映射关系:
merchant_b_id -> app_auth_token
merchant_b_id -> app_refresh_token
merchant_b_id -> token_expire_time
merchant_b_id -> authorization_status
如果系统接入了多个商户,需要根据订单所属商户选择对应的令牌,避免串户收款。
同一主体不是唯一判断条件
三方应用授权主要取决于商户授权关系、产品签约和接口权限。即使 A、B 属于同一主体,商户 B 仍需完成应用授权和当面付签约。至于是否允许非同主体商户授权,则要以应用类型、开放平台准入要求和实际审核结果为准。
小程序与三方应用是两个应用身份
小程序应用 A 的 APPID 与三方应用 APPID 不能混用:
- 服务端调用
alipay.trade.create时,使用三方应用 APPID; - 小程序只接收服务端返回的
tradeNO,并调用my.tradePay; - 不能使用小程序私钥代替三方应用私钥签名;
- 不能在前端创建交易或保存授权令牌。
如果客户端提示交易与小程序不匹配,应重点检查三方应用功能包、商户授权范围、小程序支付场景,以及开放平台要求的应用关联配置。
以服务端支付结果为准
不能直接把 my.tradePay 的成功回调作为发货或核销依据。服务端应通过支付宝异步通知或交易查询确认:
- 通知签名是否有效;
app_id是否符合预期;out_trade_no是否存在且属于商户 B;- 订单金额是否一致;
- 交易状态是否已成功;
- 通知是否已被重复处理。
做好授权失效处理
如果商户 B 取消授权、令牌到期、产品解约或账号受限,代调用可能失败。服务端需要保存授权状态,妥善保管 app_refresh_token,并按照当前开放平台规则刷新令牌。收到授权取消通知后,应立即停止为该商户创建新交易。
这套参数配置方向是正确的:三方应用负责签名,并携带商户 B 的 app_auth_token 调用 alipay.trade.create,再把返回的 tradeNO 交给小程序调用 my.tradePay。能否稳定运行,取决于商户 B 的当面付签约状态、三方应用的功能包和授权范围,以及小程序支付场景能否通过支付宝侧校验。
备注:内容仅供参考。
