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

Stripe.js V3订阅支付流程中SCA验证失败的处理方案咨询

处理Stripe SCA验证失败后的订阅支付流程问题

你遇到的这个报错完全在预期范围内——当SCA验证失败(比如用户输错了验证码、取消验证流程),对应的PaymentIntent会被标记为canceled状态,确实没法再重复确认它。不过好消息是:你完全不需要删除已创建的Stripe Customer和Subscription,这两个资源是可以复用的,只需要针对支付环节做重新处理就行。

核心思路:复用已有订阅与客户,重新发起支付验证

用户已经完成了订阅创建的核心步骤,只是支付验证没通过,所以我们只需要给这个已有的客户绑定新的支付方式,或者针对未完成的发票重新发起支付验证流程即可。

具体处理方案

1. 前端:不要直接重定向,保留上下文并提供重试入口

当handleCardPayment返回SCA相关错误时,不要直接跳回初始页面,而是在当前页面显示友好的错误提示(比如"支付验证失败,请重新尝试"),同时提供一个"重新验证支付"的按钮,让用户在同一个流程里完成重试。

示例代码调整:

// 初始化Stripe Elements(用于重新收集卡片信息)
var stripe = Stripe('pk_test_9hA8gecxBFTY3O6kUm7hl16j');
var elements = stripe.elements();
var cardElement = elements.create('card');
cardElement.mount('#card-element');

// 监听重试按钮点击
document.getElementById('retry-payment-btn').addEventListener('click', function() {
  // 先创建新的PaymentMethod
  stripe.createPaymentMethod({
    type: 'card',
    card: cardElement,
  }).then(function(pmResult) {
    if (pmResult.error) {
      // 处理卡片信息错误,比如卡号无效
      alert(pmResult.error.message);
      return;
    }

    // 把PaymentMethod ID、已有Customer和Subscription ID发送到后端
    fetch('/api/retry-subscription-payment', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        customer_id: '你的已有Customer ID',
        subscription_id: '你的已有Subscription ID',
        payment_method_id: pmResult.paymentMethod.id
      })
    }).then(function(res) {
      return res.json();
    }).then(function(data) {
      if (data.error) {
        alert(data.error.message);
        return;
      }

      // 如果后端返回需要SCA验证的PaymentIntent Secret,再次触发验证
      if (data.payment_intent_secret) {
        stripe.handleCardPayment(data.payment_intent_secret).then(function(payResult) {
          if (payResult.error) {
            alert('验证仍未通过,请再次尝试:' + payResult.error.message);
          } else {
            // 支付成功,跳转到订阅成功页面
            window.location.href = '/subscription-success';
          }
        });
      } else {
        // 无需额外验证,直接支付成功
        window.location.href = '/subscription-success';
      }
    });
  });
});

2. 后端:关联新支付方式,重新发起支付

后端收到前端的请求后,需要完成两个核心操作:

  • 将新的PaymentMethod设置为该Customer的默认支付方式
  • 针对订阅的未支付发票,创建新的PaymentIntent并尝试确认(如果需要SCA验证,就把secret返回给前端)

示例后端代码(Ruby为例,其他语言逻辑一致):

def retry_subscription_payment
  customer = Stripe::Customer.retrieve(params[:customer_id])
  subscription = Stripe::Subscription.retrieve(params[:subscription_id])
  
  # 把新的PaymentMethod设为Customer默认支付方式
  customer.invoice_settings.default_payment_method = params[:payment_method_id]
  customer.save
  
  # 获取订阅对应的未支付发票
  invoice = Stripe::Invoice.retrieve(subscription.latest_invoice)
  
  if invoice.status == 'open'
    # 创建新的PaymentIntent并尝试确认
    payment_intent = Stripe::PaymentIntent.create({
      customer: params[:customer_id],
      amount: invoice.amount_due,
      currency: invoice.currency,
      payment_method: params[:payment_method_id],
      confirm: true,
      setup_future_usage: 'off_session' # 用于后续自动扣费的SCA处理
    })
    
    # 如果需要SCA验证,返回secret给前端
    if payment_intent.status == 'requires_action'
      render json: { payment_intent_secret: payment_intent.client_secret }
    else
      render json: { success: true }
    end
  else
    render json: { success: true }
  end
rescue Stripe::StripeError => e
  render json: { error: e.message }
end

为什么不用删除Customer和Subscription?

  • Customer:记录了用户的基本信息和支付方式历史,删除后用户需要重新填写所有信息,体验极差。
  • Subscription:代表用户的订阅计划、周期、价格等核心信息,删除后需要重新创建,容易导致订阅数据不一致,后续自动扣费也会出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:38:12