支付宝服务商调用 apipay.trade.pay 报错如何解决
结论
这类问题通常与 Java 示例代码无关,更常见的原因是调用身份和商户签约关系不匹配。
服务商使用自己的应用替其他商户调用 alipay.trade.pay 时,不能只填写服务商的 app_id 和私钥。还要确认:
- 服务商应用支持第三方代调用,并且已经获得目标商户授权。
- 调用时传入了该商户授权生成的
app_auth_token。 app_id、应用私钥、支付宝公钥、网关环境和app_auth_token属于同一环境及授权关系。
开通普通网页应用并绑定当面付产品,不代表该应用可以直接替其他商户收款。商户显示“直连”或“代签约”,只能说明产品签约状态,不能代替应用授权。
问题中没有提供具体错误码和 sub_msg,因此暂时无法确定唯一故障点,可以按下面的顺序排查。
先确认调用模式
调用 alipay.trade.pay 通常有两种模式。
商户直连
商户使用自己的应用、私钥和当面付签约能力发起交易:
商户 app_id + 商户应用私钥
这种模式通常不需要传入 app_auth_token。服务商不能使用自己的应用密钥,以商户直连的方式发起调用。
服务商代调用
服务商使用自己的应用发起请求,实际交易归属于已经授权的商户:
服务商 app_id + 服务商应用私钥 + 商户 app_auth_token
此时:
app_id应填写服务商应用的app_id。- 请求使用服务商应用私钥签名。
app_auth_token必须来自当前收款商户对该服务商应用的授权。- 商户必须已经签约
alipay.trade.pay所需的当面付能力。 - 服务商应用必须支持第三方应用授权和代调用。
如果当前应用只是普通自用网页应用,不具备第三方代调用能力,就需要调整应用接入方式,或者让商户改用自己的应用直连。
正确传入商户授权令牌
在 Java SDK 中,app_auth_token 通常不写入业务 JSON,而是在执行请求时传入。
import com.alipay.api.AlipayApiException;
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 AlipayTradePayExample {
public static void main(String[] args) throws AlipayApiException {
String gatewayUrl = "https://openapi.alipay.com/gateway.do";
String appId = "服务商应用APP_ID";
String merchantPrivateKey = "服务商应用私钥";
String alipayPublicKey = "支付宝公钥";
String appAuthToken = "目标商户授权生成的APP_AUTH_TOKEN";
AlipayClient alipayClient = new DefaultAlipayClient(
gatewayUrl,
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradePayRequest request = new AlipayTradePayRequest();
AlipayTradePayModel model = new AlipayTradePayModel();
model.setOutTradeNo("ORDER_202609090001");
model.setScene("bar_code");
model.setAuthCode("用户付款码");
model.setSubject("订单支付");
model.setTotalAmount("0.01");
request.setBizModel(model);
AlipayTradePayResponse response =
alipayClient.execute(request, null, appAuthToken);
if (response.isSuccess()) {
System.out.println("支付成功");
System.out.println("trade_no=" + response.getTradeNo());
} else {
System.out.println("支付失败");
System.out.println("code=" + response.getCode());
System.out.println("msg=" + response.getMsg());
System.out.println("sub_code=" + response.getSubCode());
System.out.println("sub_msg=" + response.getSubMsg());
}
}
}
不同版本 Java SDK 提供的方法重载可能略有差异。如果当前版本没有上述三参数重载,请检查 SDK 中的 execute 方法,确认最终请求确实带上了 app_auth_token,不要自行将其写入 biz_content。
按顺序排查
1. 打印完整错误信息
只有“调用报错”这一信息,无法判断具体原因。至少应记录:
System.out.println("code=" + response.getCode());
System.out.println("msg=" + response.getMsg());
System.out.println("sub_code=" + response.getSubCode());
System.out.println("sub_msg=" + response.getSubMsg());
System.out.println("body=" + response.getBody());
排查时先看 sub_code 和 sub_msg。同时保存请求时间、服务商 app_id、商户标识和 out_trade_no,但不要在日志中完整输出私钥、付款码或 app_auth_token。
2. 检查应用类型和接口权限
先确认发起请求的 app_id 对应哪个应用,再逐项检查:
- 是否为预期的服务商应用。
- 是否支持第三方商户授权。
- 是否已经申请或配置
alipay.trade.pay所需能力。 - 应用是否已经上线,相关配置是否生效。
- 商户签约的当面付产品是否仍处于有效状态。
“网页应用已绑定当面付”和“可以替其他商户调用”并不是一回事。前者解决的是产品使用资格,后者还需要完整的第三方应用授权链路。
3. 检查商户授权关系
确认目标商户授权的是当前服务商应用,而不是其他 app_id 对应的应用。
常见问题有:
- 使用了其他商户的
app_auth_token。 - 商户重新授权后,系统仍在使用旧令牌。
- 商户已经解除授权。
- 授权范围不包含调用所需权限。
- 正式环境使用了沙箱授权令牌,或者沙箱环境使用了正式令牌。
- 将
auth_code误当成app_auth_token。
授权流程中的临时 app_auth_code 通常要先换取 app_auth_token。两者用途不同,不能混用。
4. 检查签名配置
服务商代调用时,请求仍由服务商应用私钥签名。需要核对:
app_id 服务商应用的 APP_ID
private_key 该服务商应用对应的应用私钥
alipay_public_key 该应用配置对应的支付宝公钥
sign_type 通常为 RSA2,以应用实际配置为准
charset 建议统一使用 UTF-8
以下配置不能混用:
- 服务商应用的
app_id与商户应用私钥。 - 沙箱私钥与正式环境网关。
- 应用公钥与支付宝公钥。
- 证书模式配置与普通公钥模式配置。
如果应用使用证书模式,应通过对应的证书客户端初始化,不能直接照搬普通公钥模式的示例。
5. 检查交易参数
确认身份和权限没有问题后,再检查业务参数:
out_trade_no在商户维度内应保持唯一。scene必须符合实际支付场景,例如付款码支付通常使用bar_code。auth_code应为有效且未过期的用户付款码。total_amount格式应正确,单位为元。subject不能为空。- 交易金额、行业或商户状态不能违反已签约产品的限制。
不要为了指定收款商户而随意填写 seller_id。在服务商代调用模式中,支付宝通常通过 app_auth_token 识别被授权商户。只有接口规则或具体业务场景明确要求时,才需要设置额外的商户标识参数。
常见错误方向
如果错误信息中出现以下内容,可以先检查对应位置:
| 错误方向 | 优先检查 |
|---|---|
| 无权限、产品未签约 | 商户当面付状态、服务商应用接口权限 |
| 应用授权无效 | app_auth_token 是否属于当前商户和当前应用 |
| 签名失败 | 私钥、公钥、app_id、签名方式和字符集 |
| 参数无效 | scene、auth_code、金额和必填字段 |
| 商户状态异常 | 商户账号、签约状态、授权状态 |
| 环境不一致 | 沙箱与正式网关、应用配置和授权令牌 |
| 重复订单号 | out_trade_no 是否已被使用 |
具体原因仍要以接口返回的 sub_code 和 sub_msg 为准,不要只根据表面提示修改参数。
注意事项
- “代签约”不等于“已授权服务商应用代调用”。
- “账号类型为直连”也不代表服务商可以省略
app_auth_token。 - 每个商户都需要单独授权,并保存各自对应的
app_auth_token。 - 不要将商户授权令牌写死在公共代码中,应按商户维度安全存储和读取。
- 正式环境与沙箱环境的应用、密钥、授权和网关必须一一对应。
- 排查时应提供
code、sub_code、sub_msg和脱敏后的请求参数。缺少这些信息时,只能判断常见原因,无法确认唯一解决方案。
如果当前使用的确实是普通网页应用,而且不支持第三方商户授权和代调用,通常只有两种处理方式:改用支持服务商代调用的应用接入方案,并让商户完成应用授权;或者让每个商户使用自己的应用、密钥和签约能力进行直连调用。
备注:内容仅供参考。
