Stripe订阅升级时3DS验证未完成,信用额度丢失问题求助
Stripe订阅升级后3DS中断导致信用额度消失的解决方案
问题原因
当用户触发订阅升级进入3DS验证后关闭窗口,Stripe会自动生成一张包含11美元 prorated 信用的未支付发票。这部分信用已经被分配到该未付发票上,所以再次重试升级时,系统不会重复计算信用,导致你看不到89美元的应付金额。
解决步骤
1. 先清理未支付发票
在重试订阅升级前,先查询该订阅关联的未支付发票,若存在则取消,释放已分配的信用额度:
$stripe = new \Stripe\StripeClient(STRIPE_SECRET_KEY); // 查询订阅的未支付发票 $invoices = $stripe->invoices->all([ 'subscription' => $subscription_id, 'status' => 'open', ]); // 取消所有未支付发票 foreach ($invoices->data as $invoice) { $stripe->invoices->voidInvoice($invoice->id); }
2. 调整订阅更新参数
更新订阅时,明确设置proration_behavior和payment_behavior参数,确保proration信用被正确计算并处理:
$updatedSubscription = $stripe->subscriptions->update( $subscription_id, [ 'items' => [ [ 'id' => $subscription_item_id, 'price' => $yearly_price_id, ], ], 'off_session' => true, 'proration_behavior' => 'create_prorations', // 强制生成proration 'payment_behavior' => 'default_incomplete', // 允许后续处理支付(包括3DS) 'payment_settings' => [ 'save_default_payment_method' => 'on_subscription', ], ] );
3. 处理支付验证流程
如果升级需要3DS验证,不能仅依赖off_session: true,需要捕获requires_action状态,引导用户完成验证:
if ($updatedSubscription->status === 'incomplete' && isset($updatedSubscription->latest_invoice->payment_intent)) { $paymentIntent = $updatedSubscription->latest_invoice->payment_intent; if ($paymentIntent->status === 'requires_action') { // 前端需要用paymentIntent->client_secret调用Stripe.js完成3DS验证 echo json_encode([ 'requires_action' => true, 'client_secret' => $paymentIntent->client_secret ]); exit; } }
关键说明
proration_behavior设为create_prorations会强制生成新的proration条目,确保信用额度被正确计算。payment_behavior设为default_incomplete会让订阅进入incomplete状态,而不是直接失败,方便后续处理3DS验证。- 每次重试前清理未支付发票是核心,否则已分配的信用会被锁定在未付发票中无法复用。
内容的提问来源于stack exchange,提问作者Pratik Ranpara
相关产品推荐
相关产品推荐

