
本文详解如何通过创建一次性发票并监听支付成功事件,确保客户完成付款后再更新订阅,避免未支付即升级的风险。
本文详解如何通过创建一次性发票并监听支付成功事件,确保客户完成付款后再更新订阅,避免未支付即升级的风险。
在 Stripe 中直接调用 stripe.Subscription.modify() 并设置 collection_method="send_invoice" 会立即生成待付发票,但不会阻断订阅状态变更——即:即使客户尚未付款,订阅的 plan 字段可能已更新,导致权限或服务提前切换,带来计费与功能不一致的风险。正确做法是采用两阶段原子化流程:先生成并支付一次性发票(覆盖升级差额或全量费用),再在支付确认后安全更新订阅。
✅ 推荐实现步骤
-
计算升级费用(可选)
使用 stripe.Invoice.upcoming() 预估升级产生的应计金额(如 proration 差额、新周期费用等),提升用户体验透明度:upcoming = stripe.Invoice.upcoming( customer=customer_id, subscription=subscription_id, subscription_items=[{"id": existing_item_id, "price": new_price_id}], subscription_proration_behavior="always_invoice", ) amount_due = upcoming["amount_due"] # 单位:最小货币单位(如 cents) -
创建并发送一次性发票
调用 stripe.InvoiceItem.create() 添加升级费用项,再生成发票:# 添加升级费用项(例如:计划变更差额) stripe.InvoiceItem.create( customer=customer_id, amount=amount_due, currency="usd", description=f"Upgrade to {new_plan_name}", subscription=subscription_id, # 关联当前订阅,便于后续自动结算 ) # 立即生成并发送发票(状态为 'draft' → 'open') invoice = stripe.Invoice.create( customer=customer_id, collection_method="send_invoice", days_until_due=1, auto_advance=True, # 自动尝试支付(若客户有有效支付方式) ) stripe.Invoice.finalize_invoice(invoice.id) -
监听支付成功事件,安全更新订阅
在你的 Webhook 处理器中监听 invoice.payment_succeeded 事件,仅在此时执行订阅变更:# Webhook handler (e.g., /webhook) if event["type"] == "invoice.payment_succeeded": invoice = event["data"]["object"] # 验证 invoice.subscription 存在且关联目标订阅 if invoice.get("subscription"): # 执行最终升级(此时付款已确认) stripe.Subscription.modify( invoice["subscription"], items=[{ "id": existing_item_id, # 保留原 item ID "price": new_price_id, }], proration_behavior="create_prorations", # 或 "always_invoice"(若需二次开票) # 注意:此处不再设 collection_method,因费用已结清 )
⚠️ 关键注意事项
- 禁止在前端触发订阅修改:所有敏感操作(发票创建、订阅更新)必须由后端完成,防止客户篡改价格或跳过支付。
- 幂等性保障:Webhook 可能重复投递,务必使用 event.id 去重处理,避免重复升级。
- 失败回退机制:若 invoice.payment_failed 触发,建议发送通知并提供重试入口,而非自动降级。
-
优惠券补偿(可选):若用户已预付部分费用,可在 Subscription.modify() 中传入 coupon 参数抵扣,保持账务清晰:
stripe.Subscription.modify( subscription_id, coupon="UPGRADE_DISCOUNT_2024", # 抵扣已支付的一次性发票金额 ... )
通过该方案,你将严格遵循“支付确认 → 状态变更”原则,兼顾合规性、用户体验与系统健壮性。Stripe 的事件驱动模型天然适配此流程,无需轮询或复杂状态机。

















