使用Stripe PHP包创建发票自动扣费失败,手动重试却成功的问题
我正在通过Stripe PHP包创建发票并自动向客户扣费,当前遇到异常:发票已成功创建,但存档银行卡扣费失败。但在Stripe后台找到标记为“failed”的发票,手动点击“retry charge”后扣费即可成功。发票创建流程无误且已触发扣费,但所有此类发票均需手动重试才能完成扣费,请问该现象的原因是什么?
$stripe = new \Stripe\StripeClient(config('XXXXXXXXXXXXXXXXX')); $item = $stripe->invoiceItems->create([ 'customer' => $subscription->stripe_customer, 'amount' => $total, 'currency' => 'usd', 'description' => 'Erro Coffee Subscription ' . $subscription_type->bags ]); $invoice = $stripe->invoices->create([ 'customer' => $subscription->stripe_customer, 'collection_method' => 'charge_automatically', 'auto_advance' => true, "metadata" => [ "order_type" => "subscription", "subscription_refill" => "true", "subscription_id" => $subscription->id ] ]);
1. 未主动触发即时扣费,异步自动流程存在波动
你的代码仅完成了发票项和发票的创建,虽然auto_advance: true会让发票自动从草稿转为待支付状态,但Stripe的charge_automatically模式下,自动扣费是异步触发的(通常有几分钟延迟)。如果异步扣费请求发起时,遇到客户支付方式的瞬时网络波动、发卡行临时风控拦截等情况,就会导致扣费失败;而手动重试是即时发起请求,此时临时问题已解决,因此扣费成功。
解决方案:创建发票后主动调用pay方法触发即时扣费,确保请求同步执行:
// 创建发票后立即发起扣费 $stripe->invoices->pay($invoice->id, [ // 可选:强制指定客户存档的支付方式ID,避免默认方式出错 // 'payment_method' => 'pm_xxxxxx' ]);
2. 支付方式未完成强客户认证(SCA)
若业务涉及欧盟等需强客户认证(SCA)的地区,首次自动扣费可能触发3DS验证,但异步流程无法弹出验证界面,导致扣费失败;手动重试时,Stripe会通过邮件或后台引导客户完成验证,验证通过后扣费即可成功。
解决方案:创建发票时指定payment_behavior: 'default_incomplete',并处理发票的requires_action状态,引导客户完成验证:
$invoice = $stripe->invoices->create([ 'customer' => $subscription->stripe_customer, 'collection_method' => 'charge_automatically', 'auto_advance' => true, 'payment_behavior' => 'default_incomplete', "metadata" => [ "order_type" => "subscription", "subscription_refill" => "true", "subscription_id" => $subscription->id ] ]); // 检查是否需要客户完成验证操作 if ($invoice->status === 'requires_action') { // 返回支付确认URL给前端,引导客户完成3DS验证 // $invoice->next_action->use_stripe_sdk->stripe_js }
3. 客户默认支付方式未正确配置
如果客户存档了多个支付方式但未设置默认项,Stripe自动扣费会尝试使用最近添加的支付方式,若该方式存在额度不足、过期等问题则扣费失败;手动重试时你可能选择了其他可用支付方式,因此成功。
解决方案:创建发票时明确指定要使用的支付方式,或确保客户已设置默认支付方式:
$invoice = $stripe->invoices->create([ 'customer' => $subscription->stripe_customer, 'collection_method' => 'charge_automatically', 'auto_advance' => true, 'payment_method' => $subscription->stripe_payment_method, // 传入客户存档的支付方式ID "metadata" => [ "order_type" => "subscription", "subscription_refill" => "true", "subscription_id" => $subscription->id ] ]);
4. Stripe默认自动重试策略未匹配业务需求
Stripe对失败发票有默认的自动重试计划(通常是2小时后、1天后、3天后等),若你的业务需要立即重试,而默认计划未触发时,就会出现需手动重试的情况。
解决方案:通过Stripe后台调整自动重试规则,或监听invoice.payment_failed webhook,在代码中实现自定义的即时重试逻辑。
内容的提问来源于stack exchange,提问作者Packy

