PAYATHON 2026

alipay.trade.page.pay 如何实现多商户订单合并支付?

支付老李

结论

alipay.trade.page.pay 的一次请求只能提交一笔支付宝交易,不能同时提交 A、B、C 多个支付宝商户的订单,也不能把不同商户号下的交易直接合并付款。

一次接口调用只有一个 out_trade_no、一个 total_amount 和一个收款主体。天猫式的”多店铺订单一次付款”并不是简单地传入多个订单号,而是由平台统一创建支付单,并在支付完成后按平台的结算规则拆分资金。

类似的业务通常有两种处理方式:

  • 平台已获得合规的统一收款及分账能力,可以创建一笔平台支付单,支付成功后再向各卖家分账或结算。
  • 平台没有相关能力,则由 A、B、C 分别创建交易,用户逐笔支付,不能通过 alipay.trade.page.pay 强行合并。

为什么不能直接合并

alipay.trade.page.pay 按照一笔商户订单对应一笔支付宝交易的模式工作。例如:

{
  "out_trade_no": "PAY202609090001",
  "total_amount": "300.00",
  "subject": "平台订单支付",
  "product_code": "FAST_INSTANT_TRADE_PAY"
}

其中:

  • out_trade_no 是当前调用方生成的唯一商户订单号。
  • total_amount 是本次交易的总金额。
  • 收款主体由调用接口时使用的支付宝应用及其签约商户身份决定。
  • 接口没有用于提交多个收款商户或多笔独立交易订单的通用参数。

即使把三个业务订单号拼接进 out_trade_no 或 passback_params,支付宝侧处理的仍是一笔交易,资金也只会进入这笔交易对应的收款主体。拼接订单号可以帮助平台记录业务关联,但不能实现多商户收款或资金拆分。

推荐的订单模型

如果平台已经开通并获准使用相应的收款、分账或结算能力,可以将业务订单和支付订单分成两层:

平台支付单 PAY-001,金额 300 元
├── 卖家 A 子订单 ORDER-A,金额 100 元
├── 卖家 B 子订单 ORDER-B,金额 80 元
└── 卖家 C 子订单 ORDER-C,金额 120 元

支付时,只向 alipay.trade.page.pay 提交平台支付单:

AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

request.setReturnUrl("https://example.com/pay/return");
request.setNotifyUrl("https://example.com/pay/notify");

AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setOutTradeNo("PAY-001");
model.setTotalAmount("300.00");
model.setSubject("平台订单合并支付");
model.setProductCode("FAST_INSTANT_TRADE_PAY");

request.setBizModel(model);

String form = alipayClient.pageExecute(request).getBody();

这段代码创建的是一笔总额为 300.00 元的支付交易。平台需要在自己的数据库中保存 ORDER-A、ORDER-B、ORDER-C 与该支付单之间的关系,例如:

payment_order
-------------
payment_no    = PAY-001
total_amount  = 300.00
status        = WAIT_BUYER_PAY

payment_order_item
------------------
PAY-001 | ORDER-A | SELLER-A | 100.00
PAY-001 | ORDER-B | SELLER-B |  80.00
PAY-001 | ORDER-C | SELLER-C | 120.00

支付后的处理流程

可以按以下流程实现:

  1. 用户选中多个卖家的订单。
  2. 服务端锁定这些订单,重新计算金额,并生成唯一的平台支付单。
  3. 调用 alipay.trade.page.pay,提交支付单号和合计金额。
  4. 接收支付宝异步通知并完成验签。
  5. 核对通知中的 app_id、out_trade_no、total_amount、seller_id 等信息,确认它们与本地支付单一致。
  6. 根据 trade_status 幂等更新平台支付单。
  7. 将关联的子订单更新为已支付。
  8. 如果平台已开通合规的分账产品,再按各子订单的金额执行分账或后续结算。

异步通知可以按类似逻辑处理:

public String handleNotify(Map<String, String> params) throws Exception {
    boolean verified = AlipaySignature.rsaCheckV1(
        params,
        ALIPAY_PUBLIC_KEY,
        "UTF-8",
        "RSA2"
    );

    if (!verified) {
        return "failure";
    }

    String paymentNo = params.get("out_trade_no");
    String tradeNo = params.get("trade_no");
    String tradeStatus = params.get("trade_status");
    BigDecimal paidAmount = new BigDecimal(params.get("total_amount"));

    PaymentOrder paymentOrder = paymentOrderService.findByPaymentNo(paymentNo);
    if (paymentOrder == null) {
        return "failure";
    }

    if (!paidAmount.equals(paymentOrder.getTotalAmount())) {
        return "failure";
    }

    if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {
        paymentOrderService.markPaidIdempotently(paymentNo, tradeNo);
    }

    return "success";
}

这个示例省略了事务、并发控制和完整的字段校验,不能直接当作生产环境中的完整通知处理代码。

分账能力需要单独开通

统一收款后再把资金分给多个卖家,不是 alipay.trade.page.pay 自带的功能。平台通常需要另行申请支付宝的分账、商家结算或平台类产品能力,并根据实际签约的产品调用相应接口。

平台能使用哪些产品和接口,以及分账时间、手续费、收款方绑定方式和资金限制,都取决于所属行业、商户资质和支付宝开放平台当前提供的能力。仅签约普通电脑网站支付,并不意味着平台可以先收取全部货款,再自行转给卖家。

如果尚未获得相应能力,可以选择以下方式:

  • 每个卖家使用自己的商户身份分别创建支付交易。
  • 由平台申请适用于多商户业务的支付及分账方案。
  • 联系支付宝开放平台或对应服务商,结合实际业务模式确认需要签约的产品。

退款也要按子订单设计

合并支付后,用户可能只退某个卖家的部分商品。因此,平台必须记录每个子订单的可退金额,再针对原支付宝交易发起部分退款。

例如,原交易的支付总额是 300.00 元,A 卖家子订单需要退款 30.00 元。退款请求仍关联原交易,但退款金额填写 30.00 元,同时使用唯一的退款请求号。如果资金已经分账,平台还要同步处理分账资金是否需要回退以及如何回退,具体规则以实际签约的分账产品为准。

注意事项

  • 不要在同一次 alipay.trade.page.pay 请求中放入多个商户的 AppID、商户号或签名参数。
  • 不要直接使用前端传入的订单金额计算合并金额。服务端必须根据数据库中的订单重新核算。
  • out_trade_no 应表示平台支付单,不能在不同的支付请求中重复使用。
  • 支付通知可能重复发送,更新支付单和子订单时必须保证幂等。
  • 页面同步跳转只用于展示结果。订单状态应以验签通过的异步通知或主动查询结果为准。
  • 平台统一收款涉及资金结算和合规要求,应先确认已签约的支付宝产品是否支持这种业务模式。
  • 如果业务要求在一个付款页面中分别向多个支付宝商户直接入账,普通的 alipay.trade.page.pay 无法实现。平台需要申请专门的支付及分账方案,修改接口参数解决不了这个问题。

备注:内容仅供参考。