Stripe 订阅续费失败:Smart Retries、next_payment_attempt 与 past_due 排查
Stripe 订阅首次付款成功,到续费日却进入 past_due,应用反复发送催付邮件,或者业务系统看不到预期的 next_,并不能只用“卡被拒绝”解释。需要同时查看 Subscription、Invoice、PaymentIntent、恢复规则和 webhook 处理状态。
本文目录(16 节)
先把订阅、账单和支付对象关联起来
一次续费故障至少要记录 subscription.id、latest_invoice、Invoice 的 status、attempt_count、next_、与它关联的 PaymentIntent 状态,以及最后一次失败的错误码。不要只根据 Customer 或业务订单号猜测。
调试日志中可以保存 Stripe 对象 ID、event ID、request ID和状态,但不应保存完整卡号、client secret 或 webhook secret。对 Connect 平台还必须记录对象属于平台账户还是某个 connected account。
区分首次付款失败和续费失败
Stripe 官方文档说明,对 collection_ 的订阅,创建时首次付款未完成可进入 incomplete;若约 23 小时内仍未支付,会进入终态 incomplete_。已激活订阅的后续自动扣款失败或需要用户操作时,则通常进入 past_due。
这两条路径的恢复策略不同。incomplete_ 不应被当成可继续重试的 past_due;过期首单需要根据当前价格和客户意图重新创建流程。
检查 collection_method
charge_ 和 send_invoice 的过期语义不同。前者在自动收款失败时触发重试和恢复规则;后者通常在超过 invoice due date 后进入 past_due。
如果团队期望 Smart Retries,却把订阅设成 send_invoice,调整 webhook 代码不会修复收款模式。先核对 Subscription 的实际字段、创建参数和 Dashboard 设置。
Smart Retries 不是应用层的固定计时器
Smart Retries 根据恢复设置安排后续尝试。不要在应用中用固定“24 小时后再扣”覆盖 Stripe 安排,否则可能出现同一账单多个并发收款动作。
业务系统应将 Invoice 作为重试主体,按 event ID 幂等更新本地状态。客户更新付款方式后,是否立即尝试收款应是明确的产品决策,不要一边主动支付一边等待旧重试计划。
next_payment_attempt 为空不一定是没有重试
Stripe 的 Smart Retries 文档特别提醒,使用 Automations 时,next_ 不再一定出现在 invoice.payment_failed webhook 负载中,而会在 invoice.updated 事件中更新。
因此,不能看到 payment_failed 中该字段为 null 就展示“永不重试”。记录事件创建时间、类型、Invoice ID 和对象版本,并处理 invoice.updated。需要强一致显示时,从 API 重新获取当前 Invoice,不要假设 webhook 快照是最新状态。
检查付款方式的继承顺序
Subscription 的 default_ 优先于旧的 default_source。如果订阅级别都没有配置,Invoice 还可能使用 Customer invoice_ 或相关默认来源。
客户在页面上“更新了卡”,不代表新 PaymentMethod 已设为该订阅的有效默认方式。核对 PaymentMethod 是否属于同一 Customer、Subscription 的默认字段以及当前开票上下文。不要通过创建新 Customer 规避归属问题,这会拆散订阅和历史账单。
区分 requires_payment_method 与 requires_action
续费失败后,PaymentIntent 可能是 requires_,表示需要收集新的可用方式;也可能是 requires_action,表示客户需要完成认证等操作。两者的客户界面不应显示同一句“换卡”。
监听 invoice.payment_ 并将用户引导至安全的认证流程。不要把 PaymentIntent client secret 写入 URL、邮件日志或分析平台。最终权益变更仍以 invoice.paid 或重新获取到的已支付状态为准,不以前端返回页为准。
不要仅依赖 invoice.payment_failed
invoice.payment_failed 适合记录失败和启动恢复流程,但完整状态机还需要 invoice.updated、invoice.paid、invoice.payment_ 和 customer.。Webhook 可能重复、延迟或乱序,处理器必须幂等。
使用 event ID 去重,同时对业务状态设置单调或可验证的转换规则。收到旧的 failed 事件时,不得把已经 paid 的本地状态退回失败。状态冲突时从 Stripe API 取当前对象作为对账证据。
重试用尽后的终止策略
官方文档说明,自动收款订阅用尽重试后,可根据 Dashboard 设置进入 canceled、unpaid 或仍保持 past_due。这不是 SDK 版本内的固定行为,应将恢复设置变更纳入发布审核。
canceled 是终态;unpaid 下后续 invoice 可继续生成,但不再自动尝试收款。业务系统需要明确哪个状态停止服务、哪个状态给予宽限期、哪个状态允许恢复。不要用“订阅对象还存在”作为继续供应付费权益的依据。
修复后如何恢复订阅
客户提供新付款方式后,先确认它已正确关联到 Customer 并按业务需求设为 Subscription 默认方式。然后处理最新未支付 Invoice,等待 invoice.paid 再恢复权益。
不要同时创建新订阅和支付旧 invoice,否则客户可能获得两个活动订阅。恢复端点应使用业务幂等键或严格的订阅 ID 锁,并在操作前重新读取当前 Subscription/
对账与补偿任务
Webhook 消费者宕机或时序冲突时,只靠重启服务不能证明业务状态已修复。定期对比 Stripe 中近期的 past_due、unpaid、canceled 和已 paid Invoice,与本地权益、催付状态和最后 event ID 进行校验。
补偿任务不得直接再扣款。它应只修复本地状态、补发必要通知,或把需要支付的 Invoice 引导给客户。任何主动收款都必须通过受控、幂等的专用流程。
测试不要等真实计费周期
使用 Stripe 测试环境和 Test Clocks 构建状态机回归。覆盖首次付款失败、续费失败、需要认证、更新付款方式、恢复成功、用尽重试进入每种终止策略,以及 webhook 重复和乱序。
测试断言不只检查 Stripe 状态,还要检查权益、通知去重、本地账单快照和对账任务。每个测试用唯一 Customer 和明确时钟,避免旧事件污染新用例。
上线验收清单
- 订阅的
collection_与业务预期一致。method - 首次付款与续费失败使用不同恢复分支。
invoice.payment_failed与invoice.updated都能幂等处理。next_为空时不会被误报为“不再重试”。payment_ attempt - 新 PaymentMethod 与 Customer、Subscription 归属正确。
requires_action用户可完成认证,且 client secret 不会泄露。- 只有
invoice.paid或 API 已支付证据能恢复权益。 canceled、unpaid、past_due的权益策略明确且已测试。- 对账任务能修复本地状态,不会触发重复扣款。
常见问题
next_payment_attempt 是 null 就表示 Stripe 不会重试吗?
不一定。使用 Automations 时,该字段可在 invoice.updated 而不是 invoice.payment_failed 事件中更新。
past_due 时应立即取消订阅吗?
不应一刀切。past_due 通常仍处于恢复期,应根据宽限期、风险和 Dashboard 终止策略决定权益。
更新 Customer 的卡后会自动用于当前订阅吗?
不能假设一定会。要核对 PaymentMethod 归属和 Subscription/
unpaid 与 canceled 有什么关键区别?
canceled 是终态。unpaid 下订阅仍存在,但后续账单不再自动尝试收款,业务通常应回收付费权益。
收到 invoice.paid 前端就可以先开通权益吗?
不建议。用户可能离开页面,且前端返回不是最终账务证据。应以 invoice.paid 或 API 已支付状态为准。
总结
Stripe 订阅续费失败是一个跨对象、跨事件的状态机问题。先区分首次付款与续费,核对 collection method 和默认付款方式,再通过 Invoice、PaymentIntent 和 Subscription 关联证据判断恢复路径。Smart Retries 由 Stripe 恢复设置驱动,next_ 的事件位置可因 Automations 改变。业务系统必须幂等处理乱序 webhook,以已支付证据管理权益,并用对账任务补上丢失状态。
来源资料
- Stripe Subscription Object:https:
/ / docs. stripe. com/ api/ subscriptions/ object - Stripe Billing Collection Methods:https:
/ / docs. stripe. com/ billing/ collection- method - Stripe How Subscriptions Work:https:
/ / docs. stripe. com/ billing/ subscriptions/ overview - Stripe Smart Retries:https:
/ / docs. stripe. com/ billing/ revenue- recovery/ smart- retries