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

使用Stripe嵌入式结账表单时,如何阻止关联客户邮箱的用户结账?

实现Stripe Checkout阻止重复购买的方案

Stripe Checkout并没有提供你设想的forbid_returning_customers直接参数,你需要通过事前校验+自定义逻辑来实现需求,以下是具体方案:

核心思路

提前在后端完成客户购买记录的校验,而非依赖Stripe的自动拦截,这样既能精准控制重复购买的判断规则,也能完全自定义错误提示。

分场景实现

1. 未登录访客场景

针对未登录用户,通过他们输入的邮箱查询Stripe客户库,再校验该客户是否已购买过目标产品:

  • 先根据邮箱查询是否存在对应Stripe客户
  • 若存在,进一步查询该客户是否有过对应产品的已完成结账记录
  • 若已购买,直接返回自定义错误;未购买则正常创建Checkout Session

示例代码(Node.js):

// 后端接口:处理未登录用户的结账请求
app.post('/api/checkout/guest', async (req, res) => {
  const { userEmail, priceId } = req.body;

  // 步骤1:查询该邮箱对应的Stripe客户
  const customerSearch = await stripe.customers.list({
    email: userEmail,
    limit: 1
  });

  if (customerSearch.data.length > 0) {
    const customerId = customerSearch.data[0].id;
    // 步骤2:检查该客户是否已购买过目标产品
    const existingPurchases = await stripe.checkout.sessions.list({
      customer: customerId,
      line_items: { price: priceId },
      limit: 1,
      status: 'complete' // 只筛选已完成的订单
    });

    if (existingPurchases.data.length > 0) {
      // 返回自定义错误提示
      return res.status(403).json({
        message: '你已经购买过该产品,无需重复下单'
      });
    }
  }

  // 步骤3:未购买过,创建Checkout Session
  const session = await stripe.checkout.sessions.create({
    line_items: [{
      price: priceId,
      quantity: 1,
    }],
    mode: 'payment',
    ui_mode: 'embedded',
    redirect_on_completion: 'never',
    customer_creation: 'always' // 自动为访客创建客户记录,方便后续关联
  });

  res.json({ sessionId: session.id });
});

2. 已登录用户场景

已登录用户你应该已经持有对应Stripe客户ID,直接基于客户ID校验购买记录即可:

  • 用客户ID查询是否有对应产品的已完成结账记录
  • 若已购买,返回错误;未购买则创建Session并预填充客户信息

示例代码:

// 后端接口:处理已登录用户的结账请求
app.post('/api/checkout/logged-in', async (req, res) => {
  const { customerId, priceId } = req.body;

  // 检查该客户是否已购买过目标产品
  const existingPurchases = await stripe.checkout.sessions.list({
    customer: customerId,
    line_items: { price: priceId },
    limit: 1,
    status: 'complete'
  });

  if (existingPurchases.data.length > 0) {
    return res.status(403).json({
      message: '你已经购买过该产品,无需重复下单'
    });
  }

  // 创建预填充客户信息的Checkout Session
  const session = await stripe.checkout.sessions.create({
    line_items: [{
      price: priceId,
      quantity: 1,
    }],
    mode: 'payment',
    ui_mode: 'embedded',
    redirect_on_completion: 'never',
    customer: customerId // 预填充客户邮箱等信息
  });

  res.json({ sessionId: session.id });
});

错误处理与前端交互

  • 前端在发起结账请求前,先收集用户邮箱(未登录场景),调用上述后端接口
  • 若后端返回403错误,直接在前端展示自定义提示文案(比如弹窗、页面提示)
  • 若接口返回Session ID,再初始化嵌入式Checkout组件

补充说明

  • 如果你的业务需要更严格的重复购买判断(比如同一用户账号而非邮箱),已登录场景的逻辑更可靠
  • 也可以通过Stripe Webhook监听checkout.session.completed事件,事后校验并退款,但事前拦截对用户体验更好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 08:03:16