Stripe离线会话支付(试用订阅)3DS验证未触发致扣费失败求助
问题分析与修正方案
你的操作流程
1. 创建Customer和SetupIntent
public async Task<Stripe.Customer> CreateCustomer(Stripe.Customer stripeCustomer) { var options = new CustomerCreateOptions { Email = stripeCustomer.Email, Name = stripeCustomer.Name, Phone = stripeCustomer.Phone, }; return await _customerService.CreateAsync(options); } public async Task<SetupIntent> CreateSetupIntent(string customerId) { var setupIntentOptions = new SetupIntentCreateOptions { Customer = customerId, PaymentMethodTypes = new List<string> { "card" }, Usage = "off_session" }; var setupIntent = await _setupIntentService.CreateAsync(setupIntentOptions); return setupIntent; }
2. Stripe JS关联卡片到SetupIntent
const stripeCardElement: StripeCardElement = this.card!.element; this.stripeService.confirmCardSetup('seti_*****', { payment_method: { card: stripeCardElement, billing_details: { name: 'Jenny Rosen', } }, });
3. 创建带试用期的订阅
var optionsSubscription = new SubscriptionCreateOptions { Customer = customerId, ProrationBehavior = "none", Items = new List<SubscriptionItemOptions> { new SubscriptionItemOptions { Price = priceId } }, DefaultPaymentMethod = "pm_******", CollectionMethod = "charge_automatically", PaymentBehavior = "allow_incomplete", Currency = "usd", TrialEnd = DateTime.Now.AddSeconds(30), OffSession = true, }; optionsSubscription.AddExpand(SubscriptonCreateOptionExpand); var newSubscription = await _subscriptionService.CreateAsync(optionsSubscription);
核心错误点
SetupIntent未强制触发SCA验证
你使用的「3DS Required」测试卡属于需要强客户认证(SCA)的场景,但创建SetupIntent时未明确要求在卡片绑定阶段完成3DS验证,导致保存的PaymentMethod未通过SCA认证,后续off_session自动扣费会直接被拒绝。confirmCardSetup未处理requires_action分支
调用confirmCardSetup后,若返回的SetupIntent状态为requires_action,说明需要弹出3DS验证窗口,但你的代码未处理该逻辑,直接跳过了验证步骤,导致PaymentMethod处于未认证状态。OffSession支付的逻辑矛盾
订阅创建时设置OffSession=true,但未确保PaymentMethod已完成SCA认证。Stripe在off_session场景下无法主动触发客户交互的3DS验证,因此直接拒绝扣费。
修正方案
1. 修改SetupIntent创建逻辑,强制触发3DS验证
添加RequestThreeDSecure="automatic",确保需要SCA的卡片在绑定阶段完成验证:
public async Task<SetupIntent> CreateSetupIntent(string customerId) { var setupIntentOptions = new SetupIntentCreateOptions { Customer = customerId, PaymentMethodTypes = new List<string> { "card" }, Usage = "off_session", PaymentMethodOptions = new SetupIntentPaymentMethodOptions { Card = new SetupIntentPaymentMethodOptionsCard { RequestThreeDSecure = "automatic" } } }; return await _setupIntentService.CreateAsync(setupIntentOptions); }
2. 完整处理confirmCardSetup的返回结果
必须处理requires_action状态,完成3DS验证流程后再创建订阅:
this.stripeService.confirmCardSetup('seti_*****', { payment_method: { card: stripeCardElement, billing_details: { name: 'Jenny Rosen' } } }).then((result) => { if (result.error) { // 处理绑定错误 return; } const setupIntent = result.setupIntent; if (setupIntent.status === 'succeeded') { // 验证完成,调用后端创建订阅 createSubscription(setupIntent.payment_method); } else if (setupIntent.status === 'requires_action') { // 触发3DS验证弹窗 return this.stripeService.handleCardSetup(setupIntent.client_secret); } }).then((verificationResult) => { if (verificationResult?.setupIntent.status === 'succeeded') { // 验证通过,创建订阅 createSubscription(verificationResult.setupIntent.payment_method); } });
3. 订阅创建的前置校验
仅在SetupIntent状态为succeeded(即PaymentMethod完成SCA认证)后,再调用后端创建订阅,确保后续自动扣费符合SCA要求。
内容的提问来源于stack exchange,提问作者mtdev
相关产品推荐
相关产品推荐

