PAYATHON 2026

支付宝关闭订单接口提示 ACQ.TRADE_NOT_EXIST 怎么处理?

支付小周

明确结论

alipay.trade.close 只能关闭支付宝侧已经创建且仍未支付的交易。

这两个错误分别表示:

  • ACQ.TRADE_NOT_EXIST:支付宝侧没有找到对应交易。常见情况是支付请求只生成了收银台页面或支付链接,但用户尚未进入收银台,因此支付宝交易还没有真正创建。订单号、应用或环境不一致也会导致这个错误。
  • ACQ.REASON_ILLEGAL_STATUS:交易已经支付成功,当前状态不允许关闭。对于已支付订单,应调用退款接口,不能再调用关闭接口。

正确的处理方式是先查询支付宝交易状态。交易存在且未支付时调用关闭接口;交易已经支付时,根据业务需要发起退款;交易不存在时,通常关闭本地订单即可,必要时可以稍后再次查询确认。

为什么支付接口成功后仍提示交易不存在

“支付接口调用成功”不等于”支付宝交易已经创建”。

以 alipay.trade.page.pay、alipay.trade.wap.pay 等页面支付产品为例,接口返回成功通常只表示系统已经生成跳转表单或支付地址。支付宝侧的实际交易可能要等用户打开收银台后才会创建。

如果用户一直没有跳转到支付宝收银台,此时直接调用:

alipay.trade.close

就可能返回:

ACQ.TRADE_NOT_EXIST

还需要排查以下情况:

  • out_trade_no 与发起支付时使用的值不一致;
  • 查询或关闭订单时使用了不同的 app_id;
  • 一个请求发往沙箱环境,另一个请求发往正式环境;
  • 使用 trade_no 时,传入的值不是支付宝交易号;
  • 支付请求刚刚发出,交易数据暂时无法查询;
  • 支付请求并未被支付宝成功受理,只是本地程序完成了表单生成。

本地数据库中有这笔订单,不代表支付宝侧也已经创建了对应交易。

为什么支付成功后不能关闭

支付成功后,交易通常已经进入 TRADE_SUCCESS 状态。关闭接口只能终止未支付交易,无法撤销已经完成的付款,因此会返回:

ACQ.REASON_ILLEGAL_STATUS

如果需要把已支付的款项退还给用户,应调用:

alipay.trade.refund

不能用关闭接口代替退款。

推荐的处理流程

1. 先关闭本地支付入口

订单超时或业务决定取消订单时,先将本地订单状态改为”关闭中”或”已关闭”,同时禁止系统再次生成支付参数。更新状态时应使用条件更新,避免支付回调并发执行并覆盖已支付状态。

例如:

UPDATE orders
SET status = 'CLOSING'
WHERE order_no = ?
  AND status = 'WAIT_PAY';

只有受影响行数为 1 时,才继续执行后续关闭流程。

2. 查询支付宝交易

调用:

alipay.trade.query

建议使用发起支付时的同一个 out_trade_no,并确认 app_id、网关环境和商户身份一致。

根据查询结果分别处理:

查询结果处理方式
WAIT_BUYER_PAY调用 alipay.trade.close
TRADE_SUCCESS 或 TRADE_FINISHED不再关闭;如需退钱,调用退款接口
TRADE_CLOSED本地订单可直接标记为已关闭
ACQ.TRADE_NOT_EXIST支付宝侧没有可关闭的交易,关闭本地订单即可;如果时序尚不确定,可以延迟复查
网络异常或未知结果不要直接认定关闭成功,应重新查询

不同支付宝产品的交易状态和可执行操作可能存在差异,应以当前产品的接口文档和实际查询结果为准。

3. 关闭仍处于待支付状态的交易

下面是支付宝 Java SDK 的典型调用方式。SDK 类名和响应字段应以项目实际使用的 SDK 版本为准。

AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
queryRequest.setBizContent(
    "{\"out_trade_no\":\"" + outTradeNo + "\"}"
);

AlipayTradeQueryResponse queryResponse = alipayClient.execute(queryRequest);

if (queryResponse.isSuccess()) {
    String tradeStatus = queryResponse.getTradeStatus();

    if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
        AlipayTradeCloseRequest closeRequest = new AlipayTradeCloseRequest();
        closeRequest.setBizContent(
            "{\"out_trade_no\":\"" + outTradeNo + "\"}"
        );

        AlipayTradeCloseResponse closeResponse =
            alipayClient.execute(closeRequest);

        if (closeResponse.isSuccess()) {
            // 将本地订单更新为已关闭
        } else {
            // 记录 code、sub_code、sub_msg,随后重新查询最终状态
        }
    } else if ("TRADE_CLOSED".equals(tradeStatus)) {
        // 支付宝交易已经关闭,同步更新本地状态
    } else if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {
        // 已支付,不能调用关闭接口
        // 如业务确实需要退回款项,应进入退款流程
    }
} else if ("ACQ.TRADE_NOT_EXIST".equals(queryResponse.getSubCode())) {
    // 支付宝侧尚无此交易。
    // 可关闭本地订单;如果可能存在请求时序问题,应安排延迟复查。
} else {
    // 网络、签名、权限或其他异常,保留原始响应并进行重试或人工处理
}

实际项目中不要直接拼接 JSON。建议使用 JSON 序列化组件,避免订单号中的特殊字符导致格式错误。

如何处理”交易不存在”与支付回调并发

不能直接把 ACQ.TRADE_NOT_EXIST 当作永久结论,因为可能出现以下时序:

  1. 系统发出支付请求;
  2. 关闭任务开始查询,此时暂时得到交易不存在;
  3. 用户随后打开此前生成的支付页面;
  4. 支付宝侧创建交易,用户完成付款。

关闭本地订单后,还应采取以下措施:

  • 用户支付前,再次检查本地订单是否仍允许付款;
  • 不再为已关闭订单返回新的支付链接或支付表单;
  • 对 ACQ.TRADE_NOT_EXIST 安排一次或多次延迟查询;
  • 收到支付异步通知时,通过条件更新判断订单能否转为已支付;
  • 如果本地订单已经关闭,却收到了真实的支付成功通知,不要忽略,应转入异常支付或自动退款流程;
  • 关闭接口超时或返回未知异常时,应通过查询确认最终状态,不要反复修改本地状态。

注意事项

关闭订单、支付回调和主动查询可能同时发生,因此订单状态必须以幂等方式更新。建议保存以下信息,便于排查问题:

  • 商户订单号 out_trade_no;
  • 支付宝交易号 trade_no;
  • app_id 和使用的网关环境;
  • 接口返回的 code、sub_code、sub_msg;
  • 请求时间、查询时间和回调时间;
  • 本地订单状态变更记录。

判断原则很直接:支付宝侧没有交易时,不需要调用关闭接口;存在未支付交易时,调用 alipay.trade.close;交易已经支付时,只能保留交易或按业务规则退款。

备注:内容仅供参考。