PAYATHON 2026

支付宝如何实现用户确认收货后再向商户到账?

支付阿杰

结论

可以通过支付宝的“分账冻结 + 订单结算”能力实现。

用户付款时,在支付请求中开启分账资金冻结,按照支付宝为该业务开通的规则冻结待分账资金。用户确认收货后,服务商再调用 alipay.trade.order.settle,将冻结的资金分给商户。

这并不等于把支付宝支付改成通常所说的 T+1 到账,也不意味着平台可以自行托管商户资金。支付交易仍会实时成功,但符合条件的资金会暂时处于分账冻结状态,商户在服务商发起分账结算前不能自由支配这部分资金。

为什么不能直接设置成 T+1

“用户确认收货后到账”和“T+1”解决的不是同一个问题:

  • T+1 通常指支付宝余额向银行卡结算的周期。
  • 确认收货后到账涉及交易资金控制,需要使用分账冻结、订单结算等产品能力。
  • 只把提现或银行卡结算周期改为 T+1,无法阻止商户使用已经进入支付宝账户的资金。

支付宝普通支付默认即时完成,不能通过一个到账周期参数将其改成通用的担保交易。服务商也不能先把消费者资金留在平台账户中,再通过转账付给商户。

推荐业务流程

1. 确认分账产品权限

先在支付宝开放平台确认服务商和商户具备以下能力:

  • 商户已完成服务商授权。
  • 当前应用有代商户发起支付和分账的权限。
  • 商户已开通相应的分账或订单结算产品。
  • 支付产品支持分账资金冻结。
  • 分账接收方、分账比例和金额符合支付宝配置的业务规则。

“已开通分账”不一定意味着同时开通了“支付时冻结资金”。可使用哪些字段、最长冻结多久、分账上限是多少,应以应用控制台显示的产品能力和支付宝开放平台对应接口文档为准。

2. 支付时冻结待分账资金

创建支付订单时,需要按照已开通产品的接口要求传入分账冻结标识。常见做法是在支付请求的 extend_params 中设置:

{
  "out_trade_no": "PAY202609090001",
  "total_amount": "100.00",
  "subject": "商品订单",
  "seller_id": "2088XXXXXXXXXXXX",
  "extend_params": {
    "royalty_freeze": "true"
  }
}

其中:

  • seller_id 应当是本次收款交易对应的支付宝商户。
  • royalty_freeze 表示按照分账产品规则,冻结可用于后续分账的资金。
  • 能否冻结全部订单金额,以及平台手续费如何处理,应以商户实际签约规则为准。
  • 某些支付产品或新版接口可能使用不同的请求结构,应以实际接入接口文档为准。

不能只在本地数据库中把订单标记为“未结算”。如果支付请求没有真正触发支付宝侧的资金冻结,本地状态无法限制商户使用这笔资金。

3. 等待用户确认收货

支付成功后,将业务订单更新为“待收货”,暂时不要发起最终分账。

确认收货可以由以下任一事件触发:

  • 用户主动点击确认收货;
  • 物流签收后经过约定时间自动确认;
  • 售后或争议处理完成;
  • 超过业务规定的最长确认期限。

确认前需要检查退款、关闭、投诉和售后状态,避免退款与分账同时发生。

4. 确认收货后调用订单结算接口

用户确认收货后,调用:

alipay.trade.order.settle

示例请求参数如下:

{
  "out_request_no": "SETTLE202609090001",
  "trade_no": "20260909220014XXXXXXXXXX",
  "royalty_parameters": [
    {
      "trans_in_type": "userId",
      "trans_in": "2088XXXXXXXXXXXX",
      "amount": "90.00",
      "desc": "用户确认收货后结算给商户"
    },
    {
      "trans_in_type": "userId",
      "trans_in": "2088YYYYYYYYYYYY",
      "amount": "10.00",
      "desc": "平台服务费"
    }
  ],
  "royalty_finish": "true"
}

各参数含义如下:

  • out_request_no:本次结算的请求号,必须保持唯一,并作为幂等键保存。
  • trade_no:支付宝支付交易号,不是业务系统中的 out_trade_no。
  • royalty_parameters:实际的分账明细。
  • trans_in:分账接收方标识。
  • amount:分账金额。
  • royalty_finish:是否完成本笔交易的全部分账。设为 true 前,需要确认后续不再追加分账。

接收方类型以及是否需要提前绑定分账关系,取决于商户签约的分账产品,不能直接填写任意支付宝账号。

Java 调用示例

下面使用支付宝 Java SDK 的传统接口形式展示请求结构。SDK 类名和构造方法可能因版本不同而变化,应以项目实际依赖为准。

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeOrderSettleRequest;
import com.alipay.api.response.AlipayTradeOrderSettleResponse;

public class AlipayOrderSettlement {

    public static void main(String[] args) throws Exception {
        AlipayClient alipayClient = new DefaultAlipayClient(
            "https://openapi.alipay.com/gateway.do",
            "YOUR_APP_ID",
            "YOUR_APP_PRIVATE_KEY",
            "json",
            "UTF-8",
            "ALIPAY_PUBLIC_KEY",
            "RSA2"
        );

        AlipayTradeOrderSettleRequest request =
            new AlipayTradeOrderSettleRequest();

        request.setBizContent("""
        {
          "out_request_no": "SETTLE202609090001",
          "trade_no": "20260909220014XXXXXXXXXX",
          "royalty_parameters": [
            {
              "trans_in_type": "userId",
              "trans_in": "2088XXXXXXXXXXXX",
              "amount": "90.00",
              "desc": "用户确认收货后结算给商户"
            }
          ],
          "royalty_finish": "true"
        }
        """);

        AlipayTradeOrderSettleResponse response =
            alipayClient.execute(request);

        if (response.isSuccess()) {
            System.out.println("结算受理成功:" + response.getBody());
        } else {
            System.out.println(
                "结算失败,code=" + response.getCode()
                + ", subCode=" + response.getSubCode()
                + ", subMsg=" + response.getSubMsg()
            );
        }
    }
}

在生产环境中,不能只根据 HTTP 状态码或 isSuccess() 更新订单。还需要保存支付宝返回的 code、sub_code、请求号和交易号。遇到超时或结果不明确时,应查询实际处理结果。

状态控制建议

可以把支付和结算拆成两个独立状态:

待支付
  ↓
支付成功、资金待分账
  ↓
待确认收货
  ↓
结算处理中
  ↓
分账完成

同时设置以下保护条件:

只有当:
支付成功
且订单已确认收货
且不存在退款处理中
且不存在有效售后
且未成功结算
时,才允许调用结算接口。

out_request_no 必须固定生成并持久化。同一笔结算因网络超时需要重试时,应继续使用原请求号,不能每次生成新值,否则可能导致重复请求,也会增加结果核对的难度。

退款和售后处理

如果用户在确认收货前申请退款,应先停止结算流程,再根据支付宝分账产品的规则处理冻结资金和退款。

如果分账完成后发生退款,通常不能按普通未分账订单直接处理,可能需要分账回退、资金退回,或由相关参与方承担退款资金。具体支持哪些回退接口以及相应期限,取决于实际签约产品。

以下场景需要分别处理:

  • 分账前退款;
  • 分账处理中退款;
  • 分账完成后退款;
  • 部分退款;
  • 多接收方分账后的退款。

每种场景都应单独设计状态机,不能只依赖一个“是否确认收货”字段。

其他注意事项

  • 分账冻结受产品期限和资金规则限制,不能无限期等待用户确认收货。
  • 分账总金额不能超过支付宝允许结算的可分账金额。
  • 支付宝手续费、退款金额和已经结算的金额,都会影响剩余可分账金额。
  • 不要把平台支付宝账户当作资金池,再用转账模拟担保支付。
  • royalty_finish 将分账标记为完成后,通常不能再假设后续仍可追加分账。
  • 支付通知只能证明支付结果,不能代替结算结果。
  • 沙箱与生产环境的产品权限可能不同。上线前,需要使用已签约的生产商户验证完整流程。
  • 如果控制台只有普通分账权限,没有分账冻结或订单结算权限,需要联系支付宝服务商支持渠道申请或确认适用产品,无法只靠修改接口参数实现。

对于当前的服务商模式,正确的处理方式是:支付时开启支付宝侧的分账资金冻结,确认收货后调用 alipay.trade.order.settle。如果实际签约产品不支持冻结待分账资金,现有的普通支付加普通分账就无法真正做到“确认收货后商户才能使用资金”,需要调整支付宝产品签约方案。

备注:内容仅供参考。