APP支付退款仅传out_trade_no提示支付宝交易号不存在
结论
退款接口可以只传 out_trade_no,不需要同时提供支付宝交易号。出现“支付宝交易号不存在”时,通常不是因为缺少 trade_no,而是支付宝无法在当前请求对应的交易上下文中找到这笔商户订单。
可以优先检查:
out_trade_no是否以字符串形式放在biz_content中。- 退款请求使用的
app_id、支付宝环境和收款账号是否与原支付交易一致。 - 订单号是否因整数精度、类型转换或多余空格发生变化。
- 原支付是否成功,以及该订单是否属于当前应用。
- SDK 字段映射是否正确,商户订单号有没有被误传到
trade_no。
如果已经取得支付宝交易号 2021123122001405421404780777,可以直接使用 trade_no 发起退款。排查订单关联问题时,这也是最直接的方式。
两个订单号的区别
退款接口中的两个字段含义不同:
| 参数 | 含义 | 示例 |
|---|---|---|
out_trade_no | 商户系统生成的订单号 | 202112311352268842 |
trade_no | 支付宝生成的交易号 | 2021123122001405421404780777 |
两个字段不能同时为空,提供其中一个即可。注意不要传反:
{
"out_trade_no": "202112311352268842",
"refund_amount": "0.01"
}
也可以使用:
{
"trade_no": "2021123122001405421404780777",
"refund_amount": "0.01"
}
如果两个字段都传,它们必须指向同一笔交易。实际调用时通常选择其中一个,以免发生字段冲突。
为什么只传 out_trade_no 仍可能查询不到交易
1. 退款请求与原支付使用了不同的 app_id
out_trade_no 是商户侧订单号。支付宝还需要结合应用和商户身份等信息定位交易。如果支付与退款使用了不同应用的密钥或 app_id,即使订单号没有问题,也可能找不到原交易。
需要核对:
- APP 支付时使用的
app_id - 退款时使用的
app_id - 应用绑定的支付宝账号
- 应用私钥及支付宝公钥配置
2. 支付和退款不在同一个环境
沙箱环境与正式环境的数据彼此隔离。如果支付发生在正式环境,退款请求却发到了沙箱网关,支付宝就无法查到这笔交易。
请确认支付和退款使用的是同一个网关环境。
3. out_trade_no 没有放入 biz_content
调用 alipay.trade.refund 时,业务参数需要放在 biz_content 中。如果将 out_trade_no 作为普通公共参数拼接在请求外层,SDK 或网关可能无法正确解析。
业务参数的结构应类似:
{
"out_trade_no": "202112311352268842",
"refund_amount": "0.01"
}
这段 JSON 应作为 biz_content 提交。
4. 订单号被当成数字处理
202112311352268842 是一个 18 位订单号,已经超过 JavaScript 的安全整数范围:
Number.MAX_SAFE_INTEGER = 9007199254740991
如果前端或 Node.js 程序将订单号写成数字:
const outTradeNo = 202112311352268842;
它可能在序列化前就已经丢失精度。订单号从生成、存储到传输都必须使用字符串:
const outTradeNo = "202112311352268842";
在 JSON 中也要加引号:
{
"out_trade_no": "202112311352268842",
"refund_amount": "0.01"
}
5. 原交易不属于当前收款主体
在服务商模式、代商户调用或应用授权调用等场景中,还要确认退款请求使用的授权主体、收款商户与原支付一致。仅凭一个商户订单号,无法跨应用或跨商户查询其他主体的交易。
正确的请求示例
使用支付宝 Java SDK 时,可以通过支付宝交易号发起退款:
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.setBizContent("""
{
"trade_no": "2021123122001405421404780777",
"refund_amount": "0.01",
"out_request_no": "REFUND_202112311352268842_001"
}
""");
AlipayTradeRefundResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
System.out.println("退款请求成功");
} else {
System.out.println("code: " + response.getCode());
System.out.println("subCode: " + response.getSubCode());
System.out.println("msg: " + response.getMsg());
System.out.println("subMsg: " + response.getSubMsg());
}
只使用商户订单号时:
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.setBizContent("""
{
"out_trade_no": "202112311352268842",
"refund_amount": "0.01",
"out_request_no": "REFUND_202112311352268842_001"
}
""");
AlipayTradeRefundResponse response = alipayClient.execute(request);
out_request_no 是商户退款请求号。一次性全额退款是否必须填写该字段,应以当前接口文档和具体业务场景为准。对于部分退款或同一笔交易的多次退款,建议为每次退款生成唯一值;重试同一次退款时则继续使用原值,避免重复受理。
建议的排查步骤
- 先使用支付宝交易号
2021123122001405421404780777调用退款接口。 - 确认
refund_amount以字符串"0.01"传递。 - 打印签名前的完整
biz_content,检查订单号是否发生了精度变化。 - 核对支付和退款使用的
app_id、网关环境及商户身份。 - 调用交易查询接口,分别使用
trade_no和out_trade_no查询原订单。 - 如果
trade_no能查到而out_trade_no查不到,重点检查原支付请求中实际提交的商户订单号,以及当前退款请求所属的应用或授权主体。 - 如果两个编号都查不到,优先排查环境、应用身份、授权关系和原支付状态。
不要仅凭错误描述认定必须补传 trade_no。按照参数约束,单独传入正确的 out_trade_no 是合法的。该错误表示支付宝没有在当前请求上下文中找到对应交易。如果已有准确的 trade_no,可以先用它完成退款,再继续核对商户订单号和应用配置。
备注:内容仅供参考。
