You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node.js中实现基于Stripe Checkout的多关联账户付款?

多关联账户的Stripe Checkout Session付款改造方案

问题背景

购物车包含来自不同卖家的商品,需向多个已关联主账户的卖家付款。此前单卖家场景通过Checkout Session结合payment_intent_data.transfer_data实现付款,但该方式无法直接支持多卖家,需要调整逻辑适配多账户转账需求。

核心思路

Stripe Checkout Session的payment_intent_data.transfer_data仅支持指定单个收款账户,因此需结合Transfer Group和Webhook异步处理:

  1. 创建Checkout Session时指定统一的transfer_group,不设置单个收款账户;
  2. 监听付款成功的Webhook事件(checkout.session.completed),在事件触发后批量向每个卖家发起转账,所有转账关联同一个transfer_group。

改造后的代码实现

1. 创建支持多卖家的Checkout Session

const cart = await Cart.findById(record.cartId);
const currency = 'usd';
// 计算购物车总金额
const totalAmount = cart.prices.reduce((sum, price) => sum + price, 0);
// 计算平台总手续费(示例为总金额的10%)
const totalPlatformFee = Math.ceil(totalAmount * 10);

const session = await stripe.checkout.sessions.create({
  mode: "payment",
  // 生成购物车所有商品的line_items,显示卖家和商品信息
  line_items: await Promise.all(cart.items.map(async (item, index) => {
    const partner = await Partner.findById(item);
    const seller = await Seller.findOne({ user: partner.user });
    return {
      price_data: {
        currency: currency,
        product_data: {
          name: `${seller.shopName} - ${item.productName}`,
        },
        unit_amount: Math.ceil(cart.prices[index] * 100),
      },
      quantity: 1,
    };
  })),
  // 设置统一转账组ID,关联后续所有转账操作
  transfer_group: record._id,
  payment_intent_data: {
    application_fee_amount: totalPlatformFee,
    // 不设置transfer_data.destination,避免指定单一收款方
  },
  success_url: `${domainURL}/payment/success?session_id={CHECKOUT_SESSION_ID}`,
  cancel_url: `${domainURL}/payment/cancelled`,
});

return res.json({ url: session.url });

2. 监听付款成功事件并批量转账

通过Stripe Webhook监听checkout.session.completed事件,确保仅在付款成功后执行转账:

app.post('/webhook/stripe', express.raw({ type: 'application/json' }), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;

  try {
    event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  if (event.type === 'checkout.session.completed') {
    const session = event.data.object;
    const transferGroup = session.transfer_group;
    // 根据转账组ID获取对应的订单和购物车信息
    const orderRecord = await YourOrderModel.findOne({ _id: transferGroup });
    const cart = await Cart.findById(orderRecord.cartId);
    const currency = 'usd';

    const transfers = [];
    for (let i = 0; i < cart.items.length; i++) {
      const item = cart.items[i];
      const partner = await Partner.findById(item);
      const seller = await Seller.findOne({ user: partner.user });
      const stripeDestination = seller.stripe_account.id;
      const itemPrice = cart.prices[i];

      // 向当前卖家发起转账
      const transfer = await stripe.transfers.create({
        amount: Math.ceil(itemPrice * 100),
        currency: currency,
        destination: stripeDestination,
        transfer_group: transferGroup,
      });
      transfers.push(transfer.id);
    }

    // 将转账记录保存到订单中,便于后续对账
    await YourOrderModel.findByIdAndUpdate(transferGroup, { completedTransfers: transfers });
  }

  res.json({ received: true });
});

关键注意事项

  • Transfer Group的作用:将Payment Intent与后续所有转账绑定,Stripe会确保只有当付款成功后,关联的转账才会被执行,避免付款失败却发起转账的风险。
  • 异步转账的必要性:Checkout Session仅负责发起付款流程,实际付款成功是异步事件,必须通过Webhook触发转账,不能在创建Session后立即执行。
  • 手续费灵活配置:示例中设置了总平台手续费,若需按单个商品抽成,可在创建每个transfer时单独指定application_fee_amount,替代Payment Intent中的总手续费设置。

内容的提问来源于stack exchange,提问作者Mad Devil Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:34:50