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

Stripe报错:Checkout Session不存在但ID已在控制台显示

解决StripeInvalidRequestError:No such checkout.session错误

问题根源

你错误地将Payment Intent的ID(pi_开头的标识)当成了Checkout Session的ID传入stripe.checkout.sessions.retrieve()方法。从Webhook日志可以看到,pi_3OjTAGAHrCXdaN2D11vQGxvG的object字段是payment_intent,并非checkout.session,所以用这个ID查询结账会话必然报错。

修复方案

1. 推荐方案:监听checkout.session.completed事件

这是最直接的方式,当结账会话完成时,Stripe会触发checkout.session.completed事件,事件对象中包含完整的会话信息,无需额外查询:

修改Webhook的事件处理逻辑:

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

  // Function to update plan in supabase db
  const updateUserPlan = async (customerEmail) => {
    console.log("Trying to update user plan using the updateUserPlan function");
    try {
      console.log("inside of updateUserPlan try block");

      const { data: updateData, error: updateError } = await supabase
      .from('accounts')
      .update({ Plan: 'Standard' })
      .eq('email', customerEmail)

      if (updateError) {
        console.error("Error updating user plan", updateError);
      }

      if (updateData) {
        console.log("updated user plan", updateData);
      }
    } catch (error) {
      console.error("Error with the updating userplan function", error);
    }
  }

  try {
    event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
  }
  catch (error) {
    return res.status(400).send(`Webhook Error: ${error.message}`);
  }
  // Handle the event
  switch (event.type) {
    // 新增/替换为该事件监听
    case 'checkout.session.completed': {
      const completedSession = event.data.object;
      console.log("checkout session completed", completedSession);
      
      // 获取客户邮箱
      const customerId = completedSession.customer;
      const customer = await stripe.customers.retrieve(customerId);
      const customerEmail = customer.email;

      // 直接判断会话模式
      if (completedSession.mode === "subscription") {
        console.log("checkout mode is subscription");
        updateUserPlan(customerEmail);
      } else {
        console.log("Skipping user plan update for payment mode");
      }
      break;
    }
    case 'payment_intent.succeeded': {
      // 保留原逻辑(如果有其他需求),否则可以移除
      const paymentIntentSucceeded = event.data.object;
      console.log("webhooks: payment succeeded", paymentIntentSucceeded);
      break;
    }
    default:
      // Unexpected event type
      return res.status(400).end();
  }
  // Return a 200 response to acknowledge receipt of the event
  res.status(200).send("webhook recieved request.");
})

2. 备选方案:通过元数据关联Payment Intent和Checkout Session

如果需要保留payment_intent.succeeded事件监听,可以在创建Checkout Session时,将会话ID存入Payment Intent的元数据:

修改创建Checkout Session的代码:

// Endpoint to create checkout sessions for one-off payments
app.post("/create-checkout-payment", jsonParser, urlencodedParser, async (req, res) => {
  const { customerId, priceId } = req.body;
  console.log("recieved customer and priceid for credits", customerId, priceId);

  const session = await stripe.checkout.sessions.create({
    customer: customerId,
    payment_method_types: [
      "card",
    ],
    line_items: [
      {
        price: priceId,
        quantity: 1
      }
    ],
    mode: "payment",
    success_url: 'https://localhost:5173/payment/success',
    cancel_url: 'https://localhost:5173/pricing',
    // 添加元数据存储会话ID
    payment_intent_data: {
      metadata: {
        checkout_session_id: session.id
      }
    }
  })
  res.json({ id: session.id })
})

然后在Webhook中从Payment Intent取出会话ID查询:

// 在payment_intent.succeeded事件处理中
const sessionId = paymentIntentSucceeded.metadata.checkout_session_id;
if (sessionId) {
  const session = await stripe.checkout.sessions.retrieve(sessionId);
  console.log("session:", session);
  
  // 后续判断模式的逻辑不变
  if (session.mode === "subscription") {
    console.log("checkout mode is subscription");
    updateUserPlan(customerEmail);
  } else {
    console.log("Skipping user plan update for payment mode");
  }
}

验证步骤

部署修改后的代码后,触发一次支付流程,检查Webhook日志是否能正确获取到Checkout Session信息,同时确认用户套餐更新逻辑正常执行。


内容的提问来源于stack exchange,提问作者anon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:12:03