先搞清楚一个被多数独立开发者忽略的事实:Baremetrics 行业数据显示,SaaS 业务中 20%-40% 的用户流失并非主动取消,而是因为银行卡到期、余额不足这类支付失败导致的“非自愿流失”。你的用户真想续费,只是钱没扣成。
Stripe 后台显示“订阅已取消”时,没人告诉你这到底是用完即走,还是单纯卡失效。没有催款管理的后果就是:沉默地流失了那些愿意继续掏钱的订阅者。卡失败加智能重试耗尽,等于无声的营收失血。
解决思路很直接——在 Stripe 智能重试全部失败后,靠三段代码把挽回链路接上。第一步,先回到 Stripe 控制台开启自动重试:路径是 Billing → Subscriptions and emails → Manage failed payments,启用 Smart Retries。
Stripe 的机器学习模型会帮你选最优重试时机,上限 4 次。全部失败后订阅才被取消,此时 customer.subscription.deleted 触发,到了你该出手的时候。
第二步是 Webhook 接入,在 app/api/stripe/webhook/route.ts 里监听两个事件:invoice.payment_failed 触发 handlePaymentFailed,invoice.paid 触发 handlePaymentRecovered。前者对应扣款失败,后者是用户更新支付方式并成功扣款后的状态同步。
注意签名校验不可省,直接走 constructEvent 验签,校验失败返回 400。
第三步是核心——对接 Supabase 更新用户订阅状态。handlePaymentFailed 函数先从 invoice 对象中提取 customerId,然后到 profiles 表里查 stripe_customer_id 对应的用户邮箱和名称。找到后,把 subscriptions 表的 status 更新为 past_due,同时记录 payment_failed_at 时间戳。
接着通过 stripe.billingPortal.sessions.create 生成一个可直链的管理后台,return_url 指向用户 dashboard。这一步的目的很简单:让用户点一下就能更新支付方式,别让任何多余步骤挡在续费前面。
最后一步是邮件触达。拿到 profile 中的 email 和 name 后,调用 sendPaymentFailedEmail,把 Billing Portal 链接塞进邮件发给用户。支付恢复邮件同理,invoice.paid 事件触发时调用 sendPaymentRecoveredEmail 做状态通知。整个链路环环相扣:Stripe 智能重试扛住偶发失败→重试耗尽后 Webhook 触发→Supabase 标记状态并生成恢复入口→邮件触达用户→用户点链接更新支付方式→扣款成功同步状态。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.