编程 Stripe webhook 升级 API 版本:先建一个 disabled 端点做双投递,老端点回 400 保留回滚

2026-10-25 21:06:31

Stripe webhook 升级 API 版本:先建一个 disabled 端点做双投递,老端点回 400 保留回滚

相关文档:

每个 webhook endpoint 各自固定绑定一个 API 版本,Stripe 按该版本组织发给这个端点的事件 payload。因此升级集成版本时,不只是换 SDK,端点也要一起升级。

版本由谁决定

一次请求最终使用哪个版本,按以下顺序确定:

  1. 请求里带了 Stripe-Version header,就用它;
  2. 否则用服务端 SDK 固定的版本;
  3. 再否则用账户的默认 API 版本。

账户默认版本在第一次发起 API 请求时设定,可在 Workbench 的 Overview 页查看和升级。通过 API 检索 event 时,返回结构由该事件发生当时的账户默认版本决定。

webhook endpoint 可以固定自己的版本:只要端点显式设置了版本,Stripe 发给它的所有事件都用这个版本。

服务端 SDK 的版本约束:

  • 用 Ruby/Python/PHP/Node 时,可以全局或在单次请求上设置 stripe_version。
  • 用 Java/Go/.NET 这类强类型语言时,API 调用固定使用 SDK 发布时的 API 版本,无法指定其他版本。这些 SDK 的 webhook 端点版本必须与 SDK 版本一致,否则 SDK 无法反序列化事件。

先判断目标版本有没有 breaking change

  • 2024-09-30.acacia 之前的每个 API 版本都带 breaking changes。
  • 从 2024-09-30.acacia 起,Stripe 每月发布新版本,且不含 breaking changes。
  • 每年两次发布 major release(Basil、Clover、Dahlia、Endive 等),其首个版本包含 breaking changes,升级到新的 major 可能需要改代码。
  • 当前版本是 2026-09-30.endive。Dahlia 的首个版本 2026-03-25.dahlia 引入了 breaking changes,之后的 Dahlia 版本只做增量。
  • Endive 的 changelog:从 Checkout Sessions 移除 payment method types 参数;从 Payment Intents 和 Setup Intents 移除 payment method types 参数;移除 Elements 中的 payment method types 选项;废弃 payment request button;API v1 资源的 thin events 转为 GA;统一 Subscriptions 与 Invoices 的计费周期锚点格式;支持按需暂停与恢复 Subscriptions。

升级 webhook 端点:按顺序操作

1. 新建一个 disabled 的端点

  • url:与原端点相同,加一个查询参数区分两者,例如 https://example.com/webhooks?version=2024-04-10。
  • enabled_events:与原来相同的事件集合。
  • api_version:要升到的目标版本。升到最新版本可以用 Dashboard 或 API;其他版本只能用 API 显式指定。

创建后先保持 disabled,下一步再启用。

2. 改处理代码,让它忽略发往新端点的事件

判断请求里的查询参数:旧 API 版本就照常处理;新版本就直接忽略并返回 200,避免 Stripe 重投。

3. 启用新端点

此时每个事件会被投递两次:一次用旧 API 版本,一次用新 API 版本。

4. 升级 Stripe library 到与新端点一致的版本

对照 changelog 处理 breaking changes。然后把处理逻辑反过来:查询参数是旧版本就忽略并返回 400,让 Stripe 自动重试;是新版本就正常处理。返回 400 的意义在于:万一需要回滚,事件会被重新发到旧端点。

5. 观察新端点

事件处理不正确时:先把代码回退到旧版本,临时禁用新端点,处理失败的事件(之前返回过 400 的会被 Stripe 自动全部重发),定位并修复问题,再重新启用端点继续观察。

6. 禁用旧端点,停止返回 400

旧端点一直返回 400 会影响依赖 200 响应的集成。禁用之后,Stripe 不再重投那些返回过 400 的事件。

整个灰度期间两个端点同时存活,Stripe 会把订阅的事件同时投给两边,事件处理必须幂等。

集成升级的其他动作

  • 先确定目标版本,在代码里显式指定 API 版本,不要依赖账户默认版本。
  • 用 Stripe-Version header 试跑更新的版本。
  • 在 Workbench 的 Overview 页查看集成当前用了哪些 API 版本。

Event destinations 与 snapshot events

  • snapshot events 的 payload 渲染版本由 destination 的 snapshot_api_version 属性控制,它与 SDK 的 API 版本无关。
  • thin events 的 payload 不带版本。
  • snapshot_api_version 只能在创建 event destination 时设置。要用别的版本,先新建一个配好该版本的目的地并测试,再删除原有的。
  • 迁移期间两个目的地都处于活动状态时,事件处理必须幂等,因为 Stripe 会向两者都投递订阅的事件。

API 版本实际控制什么

  • 未设置 Stripe-Version 时,你可以发送哪些参数、会收到哪些对象。
  • Stripe.js 返回对象的结构。
  • 发往 webhook 端点的对象结构。
  • Stripe 代你执行的自动化 Billing 操作,例如为新订阅周期生成 invoice。

Stripe 视为向后兼容的改动

  • 新增 API 资源。
  • 新增可选的请求参数。
  • 响应中新增属性。
  • 属性顺序变化。
  • 不透明字符串的长度或格式变化,包括 charge ID 上 ch_ 这类前缀的增删。
  • Stripe 对象 ID 最长可达 255 字符,MySQL 中应存为 VARCHAR(255) COLLATE utf8_bin 以保证大小写敏感。
  • 新增事件类型,webhook listener 必须能优雅处理不认识的事件类型。

绕开整套流程:thin events

不想处理 webhook 版本,就用 thin events。API v1 和 v2 资源都会产生 thin events,且 thin event 通知的 payload 不带版本,升级 API 版本或 SDK 时不需要改 event destination 配置。Endive changelog 中,API v1 资源的 thin events 已 GA,此前是 private preview,仅支持 API v2 资源。

复制全文 生成海报 Stripe webhook 支付 API

推荐文章

程序员茄子在线接单