stripe-node 23.0.0 升级笔记:API 版本被静默抬升、payment_method_types 移除、webhook 容差反转
版本与 pinned API version
stripe-node 23.0.0 于 2026-10-01 发布于 npm,pinned API version 从 22.6.2 的 2026-08-26.dahlia 改为 2026-09-30.endive。SDK 在未指定 apiVersion 时使用发布时的最新版本,所以单纯改 package.json 里的版本号,等于同时把发给 Stripe 的 API 版本也换掉了。
验证方式是把 SDK 的请求打到本地自建的 HTTP server 上,直接读 Stripe-Version 请求头:
const http = require('http');
const Stripe = require('stripe');
const server = http.createServer((req, res) => {
console.log(req.headers['stripe-version']);
res.setHeader('content-type', 'application/json');
res.end(JSON.stringify({ id: 'cus_test', object: 'customer' }));
});
server.listen(4242, async () => {
const stripe = Stripe('sk_test_x', { host: '127.0.0.1', port: 4242, protocol: 'http' });
await stripe.customers.create({});
});
三种组合的输出:
stripe 22.6.2 -> Stripe-Version: 2026-08-26.dahlia
stripe 23.0.0 -> Stripe-Version: 2026-09-30.endive
stripe 23.0.0 + apiVersion: '2026-08-26.dahlia' -> Stripe-Version: 2026-08-26.dahlia
钉住旧版本用:
const stripe = Stripe(process.env.STRIPE_SECRET_KEY, {
apiVersion: '2026-08-26.dahlia',
});
README 里有一条容易被略过的说明:类型只反映最新 API 版本。即使 apiVersion 钉在 2026-08-26.dahlia,TypeScript 类型仍按 23.0.0 对应的新版本生成,类型与实际响应会不一致。要么接受这层不一致,要么别把 SDK 和 API 版本拆得太久。
payment_method_types 被移除
23.0.0 的生成代码里明确写了 Remove support for payment_method_types,涉及 Checkout.SessionCreateParams、PaymentIntentConfirmParams、PaymentIntentCreateParams 等;同时在 Checkout.SessionCreateParams 与 Checkout.Session 上新增 allowed_payment_method_types。
TypeScript 下编译直接失败:
error TS2561: Object literal may only specify known properties, but 'payment_method_types' does not exist in type 'SessionCreateParams'. Did you mean to write 'payment_method_data'?
error TS2561: ... but 'payment_method_types' does not exist in type 'PaymentIntentCreateParams'.
22.6.2 下没有这个错误,反过来 allowed_payment_method_types 在 22.6.2 里不存在,所以两个版本的代码不能共用同一份类型定义。
纯 JavaScript 不报错。23.0.0 仍会把 payment_method_types[0]=card 原样放进请求体发出去,拦在编译期之外的问题就落到运行期。按 API changelog 的 2026-09-30.endive breaking changes,创建 Checkout Session 时传 payment_method_types 返回 400,错误码 payment_method_types_no_longer_supported;Payment Intent 的 create/update/confirm、Setup Intent 的 create/update 同理。
改法:
await stripe.checkout.sessions.create({
- payment_method_types: ['card'],
+ allowed_payment_method_types: ['card'],
line_items: [...],
mode: 'payment',
});
注意语义也变了:不匹配币种/金额的支付方式会被排除,而不是返回错误。错误路径变成静默少几种支付方式,测试时要看返回对象里的支付方式列表,而不是只看有没有抛异常。另外新增了 paypay 支持。
webhook 签名容差语义反转
两处变化方向相反:
stripe.webhooks.signature.verifyHeader()/verifyHeaderAsync()此前省略tolerance参数时跳过时间戳容差校验,现在默认使用Webhook.DEFAULT_TOLERANCE(300 秒)。constructEvent第四参传0以前仍按默认 300 秒校验,现在正确跳过时间戳校验。
后果分成两类:直接调用 verifyHeader 的代码从 23.0.0 起会拒绝旧签名,原本「不传 tolerance 就不校验时间戳」的路径没有了;constructEvent(..., 0) 的代码会静默变成接受重放签名。签名本身仍然验证,反转的只是时间戳这层防重放。显式传参最稳:
stripe.webhooks.signature.verifyHeader(payload, sigHeader, secret, 300);
先把调用点找出来:
grep -rnE "constructEvent(Async)?\(|verifyHeader(Async)?\(" \
--include=*.js --include=*.ts --include=*.mjs --include=*.cjs \
src/ server/ api/ 2>/dev/null
其他变更
- Node.js 18 支持结束,
engines从>=18改为>=20,最低 Node 20。 - 响应体被截断时,错误类型由
StripeAPIError改为StripeConnectionError。依赖错误类型判断是否重试的逻辑要跟着改,否则这类瞬时错误不会被重试。 ErrorType不再导出,改用Stripe.errors。Account.business_profile新增specified_commercial_transactions_act_url(日本专用)。
升级顺序
- 先 pin
apiVersion到2026-08-26.dahlia,把 SDK 升级与 API 版本升级拆成两步,出问题时能区分是哪一层引起的。 - 升到 23.0.0,修类型错误(
payment_method_types→allowed_payment_method_types)与 webhook 调用点(verifyHeader补 tolerance、constructEvent(..., 0)逐个确认意图)。 - 在 sandbox 端到端跑一遍支付,重点看被剔除的支付方式和 webhook 重放校验。
- 最后升 API 版本到
2026-09-30.endive,并检查 dashboard 里 webhook 投递设置使用的版本。
webhook 端点的独立版本
webhook 端点有独立的 api_version,而 snapshot_api_version 只能在创建目标时设置,事后改不了。所以升级要新建端点并行接收,处理程序必须幂等——同一事件可能从新旧两条路径各到一次。轻量事件(thin events)的 payload 不带版本,可以避开这一层。