支付事件回调
路径与签名
Stripe 插件提供 POST /api/auth/stripe/webhook,验证签名后更新 subscription 表。回调签名使用 STRIPE_WEBHOOK_SECRET,不能用普通 API 密钥替代。
配置目标网址为你的 APP_ORIGIN 加上该路径。插件处理的核心事件包括:
checkout.session.completed
customer.subscription.created
customer.subscription.updated
customer.subscription.deleted这些事件用于同步创建、状态、周期和取消信息。具体行为以锁定版本插件及真实事件验收为准,不能只以浏览器结账回跳为成功依据。
本地转发
stripe listen --forward-to http://localhost:4400/api/auth/stripe/webhook使用 Stripe CLI 输出的签名密钥更新 .env.local,填齐其他支付凭据并重启接口。如果 CLI 会话、账号或转发目标变化,重新核对当前签名密钥。
原始请求体
签名验证需要原始请求体。入口保护可以有界读取并保留原始字节,再交给插件;不要转换或重新序列化它。反向代理也要保留回调方法、请求体与签名头。
排查与验收
签名失败检查测试或正式模式、密钥及请求体;404 检查支付启用条件与路径;数据库未更新检查事件投递日志和迁移。
测试事件重投、乱序到达、取消和试用变化。新增积分发放等自定义处理时使用唯一事件键,不能每收到一次通知就重复加积分。当前插件订阅接入不包含一次性积分包到账处理。
锁定版本的保护与缺口
回调在原始字节验签和模式核对之后,按本人 / 组织主体获取数据库租约,再用 SDK 读取当前资源。Checkout 通知还读取当前会话并核对关联。已存在订阅走插件更新,已知唯一客户的新订阅走插件创建,保持 Better Auth 对订阅表的写入职责。历史通知只触发当前状态核对,不能直接把旧载荷写回。原始请求仍由插件真实验签;没有将新对象重新编码成签名请求。
插件创建 / 更新的短事务内检查保存结果,不一致回滚;onEvent 在提交后继续使用 uncached 数据库核对,覆盖创建、状态、方案、席位、周期、取消与日程关联。供应商读取失败或资源列表不完整返回 503;插件内部吞掉数据库错误后,保存校验仍返回非 2xx。适配器将锁定创建处理器遗漏的取消 / 结束 / 日程字段补入同一次插件创建,不另写状态表;数据库触发器静默改动状态也会被校验并回滚。每个 SDK 客户端独立包装验签方法,避免共享对象串用模式或租约。
内部事件类型用于选择当前对象的插件处理路径,不保证原通知对应的完成 / 删除钩子触发。新邮件、积分等一次性副作用需要独立持久去重与发件箱,按 I12 实施;本轮没有新增此类副作用。当前状态读取不是 Stripe 和本地数据库的原子事务,新变化依赖后续通知收敛。GET 回跳复用当前资源和保存校验;锁定版本补丁修复已可用订阅跳过更新及结束 / 日程字段遗漏。没有伪造签名事件,回跳不作为单独付款确认。
原始载荷上限为 256 KiB,超过返回 413;租约忙返回 503,旧令牌不能写插件状态。bun subscriptions:validate 验证八个实际 PostgreSQL 连接、Better Auth handler 和受控 SDK HTTP,包括七个并发通知先重试、随后均保存当前状态。bun payments:validate 在生产 Worker 验证正常事件、旧通知、读取失败和数据库故障重投,SDK 订阅读取经本地出站拦截提供受控结果,没有访问实际 Stripe。原生 Worker 另用实际注册会话验证 GET 回跳、已可用状态更新、读取 / 保存失败无跳转及修复重试;所有客户创建、Checkout / 订阅读取均为受控 SDK HTTP。两者不能证明真实收款或原生 Checkout 创建 / 门户 HTTP 已验收。
真实沙箱、年付首购界面、未知过期 Checkout 自动找回和生产绑定继续按 I6 验收。结账原请求恢复、状态权限和其他已知缺口见中文教程。