关于 api-commerce-stripe
面向编码的 Skill,指导使用 `stripe` npm 包在 TypeScript 服务端集成 Stripe,涵盖支付、账单、Webhook 和 Connect,并强调安全处理请求。
主要功能
- 01初始化带类型的 Stripe 客户端
- 02创建 Checkout Sessions 和 Payment Intents
- 03验证并处理 Webhook 事件
- 04管理客户、订阅、产品和价格
- 05使用幂等键与类型化错误处理
适用场景
- 01实现一次性或定期付款
- 02构建自定义支付流程
- 03处理异步支付事件
- 04通过 Stripe Connect 管理平台支付
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-commerce-stripe安装后在 Claude Code 中输入/api-commerce-stripe确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
metadata.yamlreference.mdexamples/connect.mdcore.mdsubscriptions.mdwebhooks.md详细介绍
Stripe 模式
快速指南: 使用
stripenpm 包处理所有服务端 Stripe 操作。始终使用原始请求体,通过constructEvent()验证 Webhook 签名,绝不要使用解析后的请求体。在所有会修改数据的请求中使用幂等键。仅在服务端保管密钥。使用instanceof Stripe.errors.StripeError处理错误。金额始终以货币的最小单位表示(例如,USD 以美分为单位)。
<critical_requirements>
关键:使用此技能前
所有代码都必须遵循项目在 CLAUDE.md 中的约定(kebab-case、命名导出、导入排序、
import type、命名常量)
(绝不能在客户端代码中暴露 STRIPE_SECRET_KEY——它只能保留在服务端)
(必须使用原始请求体,通过 stripe.webhooks.constructEvent() 验证 Webhook 签名——绝不能使用解析后的 JSON)
(必须在所有会修改数据的(POST)请求中使用幂等键,以防止重复扣款)
(必须使用 instanceof Stripe.errors.StripeError 处理所有 Stripe 错误——绝不能忽略支付错误)
(必须以货币的最小单位表示金额——USD 使用美分,而不是美元)
</critical_requirements>
自动检测: Stripe、stripe、stripe.checkout.sessions、stripe.paymentIntents、stripe.customers、stripe.subscriptions、stripe.webhooks、constructEvent、PaymentIntent、CheckoutSession、STRIPE_SECRET_KEY、STRIPE_WEBHOOK_SECRET、stripe.prices、stripe.products、stripe.refunds、stripe.transfers、stripe.accounts、Stripe.errors、idempotencyKey、payment_intent.succeeded、checkout.session.completed
适用场景:
- 创建用于一次性付款或订阅付款的 Checkout Session
- 使用 Payment Intents 构建自定义支付流程
- 处理异步支付生命周期中的 Webhook 事件
- 管理客户、支付方式和订阅
- 使用 Stripe Connect 构建市场平台
- 处理退款和争议
- 为商品目录设置产品和价格
涵盖的关键模式:
- 使用 TypeScript 类型初始化 Stripe 客户端
- Checkout Session(一次性付款、订阅、设置模式)
- Payment Intent(自定义流程、确认、扣款)
- Webhook 签名验证和事件处理
- 创建和更新客户,以及附加支付方式
- 订阅生命周期(创建、更新、取消、试用、按比例计费)
- 产品和价格(商品目录管理)
- Stripe Connect(创建账户、转账、目的地扣款)
- 使用带类型的 Stripe 错误处理错误
- 使用幂等键安全重试
不适用场景:
- 客户端 Stripe.js 或 Stripe Elements(请使用前端框架技能)
- Stripe CLI 命令或控制台配置
- 非 Stripe 支付处理商(请使用其专用技能)
详细资源:
- 有关决策框架和反模式,请参阅 reference.md
核心设置与支付:
- examples/core.md — 客户端设置、Checkout Session、Payment Intent、错误处理
Webhook 与事件:
- examples/webhooks.md — 签名验证、事件处理、幂等处理
订阅与账单:
- examples/subscriptions.md — 订阅生命周期、试用、按比例计费、按量计费
Connect 与平台:
- examples/connect.md — 关联账户、转账、目的地扣款、平台费用
## 理念
Stripe 是一个支付基础设施平台。stripe npm 包是用于与 Stripe API 交互的服务端 SDK。出于安全考虑,所有支付处理都在服务端进行。
核心原则:
- 仅限服务端 — 密钥和所有创建支付的操作绝不能在浏览器中运行。客户端仅使用 Stripe.js(这是另一个领域)来收集支付详情。
- 金额以最小单位表示 — 所有货币值均为最小货币单位的整数(USD 的美分、GBP 的便士)。
1000表示 $10.00,而不是 $1000。 - 使用幂等性保障安全 — 每个变更请求都应包含幂等键,以防网络重试导致重复扣款。Stripe 的 SDK 会在重试时自动生成密钥,但对于应用层重试,你应提供显式密钥。
- Webhook 是事实来源 — 应通过 webhook 确认支付状态,而不是轮询。Webhook 事件是确认支付成功、失败或需要执行操作的唯一可靠依据。
- 错误以类型化异常表示 — Stripe 错误会被抛出(而不是作为值返回)。使用
instanceof Stripe.errors.StripeError捕获,并按类型处理,以便向用户提供恰当的响应。 - API 版本控制很重要 — 固定 API 版本。类型反映的是最新 API 版本。使用构造函数中的
apiVersion来锁定行为。
何时使用 Stripe:
- 收款(一次性、定期、市场平台分账)
- 构建订阅计费系统
- 使用 Connect 实现平台/市场平台支付分账
- 保存支付方式以便日后扣款
何时不使用:
- 渲染客户端支付表单(Stripe.js / Elements 属于另一个领域)
- 在没有服务端的情况下处理支付(Stripe 需要服务端密钥)
- 简单的捐赠按钮(Stripe Payment Links 可能无需代码即可满足需求)
核心模式
模式 1:初始化 Stripe 客户端
创建一个单例 Stripe 客户端。从环境变量读取密钥,并固定 API 版本。完整设置请参阅 examples/core.md。
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2026-02-25.clover",
});
切勿将密钥硬编码,也不要省略 apiVersion(Stripe API 升级时,行为可能会静默变化)。
模式 2:Checkout Sessions
一次性支付使用 mode: "payment",定期支付使用 mode: "subscription"。支付页面由 Stripe 托管。成功 URL 中务必包含 {CHECKOUT_SESSION_ID}(Stripe 会自动替换此模板)。完整示例请参阅 examples/core.md。
const session = await stripe.checkout.sessions.create({
mode: "payment", // or "subscription" or "setup"
line_items: [{ price: priceId, quantity }],
success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.APP_URL}/cancel`,
});
模式 3:Payment Intents(自定义流程)
需要完全控制支付界面(例如使用 Stripe Elements)时,请使用 Payment Intents。务必使用 automatic_payment_methods(而不是旧版 payment_method_types 数组),并包含幂等键。完整示例请参阅 examples/core.md。
const paymentIntent = await stripe.paymentIntents.create(
{
amount: amountInCents,
currency,
automatic_payment_methods: { enabled: true },
},
{ idempotencyKey: `pi_${orderId}` },
);
return { clientSecret: paymentIntent.client_secret };
将参数命名为 amountInCents,以避免混淆美元和美分。向前端返回 client_secret。
模式 4:客户管理
创建客户时使用幂等键(根据电子邮件生成,以防重复)。分两步附加支付方式:先附加,再通过 invoice_settings.default_payment_method 设为默认方式。完整示例请参阅 examples/core.md。
模式 5:产品和价格
在 Stripe 的数据模型中,产品和价格是独立的资源。仅对订阅价格添加 recurring: { interval }。将金额参数命名为 amountInCents。完整示例请参阅 examples/core.md。
模式 6:退款
全额退款时省略 amount。使用 payment_intent(优先于 charge)。务必包含一个对退款金额而言唯一的幂等键。完整示例请参阅 examples/core.md。
### 模式 7:错误处理
使用 instanceof Stripe.errors.StripeCardError(以及其他错误子类)捕获错误。StripeCardError 会返回可安全展示给用户的消息和 decline_code。StripeInvalidRequestError 表示开发者错误。StripeConnectionError 和 StripeRateLimitError 可以重试。完整的错误处理模式请参见 examples/core.md。
if (error instanceof Stripe.errors.StripeCardError) {
return { success: false, message: error.message, code: error.code };
}
<red_flags>
高风险项
高优先级问题:
- 客户端代码中包含密钥 —
STRIPE_SECRET_KEY绝不能出现在浏览器包中。客户端仅使用STRIPE_PUBLISHABLE_KEY(以pk_开头)调用 Stripe.js。 - 未验证 Webhook 签名 — 如果不使用
constructEvent()进行验证,攻击者就可以发送伪造事件来完成订单、授予访问权限或修改记录。 - Webhook 未使用原始请求体 — 使用
req.body(已解析的 JSON)而不是原始请求体字符串或缓冲区,会导致签名验证静默失败。在 Express 中,请在 Webhook 路由上使用express.raw({ type: "application/json" })。 - 缺少幂等键 — 没有幂等键时,网络重试可能会产生重复扣款。创建或更新操作时,务必传入
{ idempotencyKey }。 - 使用美元金额而非美分 —
amount: 10会产生 $0.10 的扣款,而不是 $10.00。务必乘以 100,或将变量命名为amountInCents。
中优先级问题:
- 未固定 API 版本 — 如果构造函数中没有设置
apiVersion,Stripe 会使用你账户的默认版本。API 变更可能会在不提示的情况下导致集成失效。 - 使用
payment_method_types而非automatic_payment_methods— 旧式数组方式需要在新增支付方式时手动更新。现代方式是使用automatic_payment_methods: { enabled: true }。 - 吞掉 Stripe 错误 — 空的
catch块会隐藏支付失败。务必记录错误的requestId,以便与 Stripe 支持团队一起排查问题。 - 未处理
requires_action状态 — Payment Intents 可能需要 3D Secure 身份验证。确认后请检查paymentIntent.status。 - 轮询而非使用 Webhook — 循环检查支付状态并不可靠,还会浪费 API 调用。所有异步支付事件都应使用 Webhook。
常见错误:
- 同步处理 Webhook — Webhook 处理程序中的长时间运行操作会导致超时。请立即返回
200,然后异步处理。 - 未处理重复的 Webhook 事件 — Stripe 可能会多次发送同一事件。请跟踪已处理的事件 ID,确保处理逻辑具有幂等性。
- 在生产环境中使用测试密钥 — 以
sk_test_和pk_test_开头的密钥只能用于测试数据。请检查环境配置。 - 忘记为嵌套对象设置
expand— 对于关联对象,Stripe 默认只返回 ID。请使用expand: ["latest_invoice.payment_intent"]获取完整对象。
注意事项与边界情况:
- Stripe 事件不按顺序发送 —
invoice.paid可能会先于invoice.created到达。请设计不依赖事件顺序的处理程序。 - Checkout Session 的
{CHECKOUT_SESSION_ID}是字面模板 — Stripe 会在success_url中替换此占位符。请勿对其进行 URL 编码。 - 订阅按比例计费默认启用 — 在计费周期中途升级方案会自动按比例计费。传入
proration_behavior: "none"可将其禁用。 - 幂等键会在 24 小时后过期 — 过期后,同一个键会创建新请求。对于长期重试,请生成新键。
- 零小数位货币 — JPY、KRW 等货币没有小数单位。JPY 中的
amount: 500表示 500 日元,而不是 5 日元。请检查Stripe.ZERO_DECIMAL_CURRENCIES。 - Connect 转账需要
transferscapability — 关联账户在接收转账前,必须启用card_payments和transferscapabilities。 - 每个端点的 Webhook 密钥各不相同 — 每个 Webhook 端点都有自己的签名密钥。使用错误的密钥会导致所有签名验证失败。
</red_flags>
<critical_reminders>
重要提醒
所有代码都必须遵循 CLAUDE.md 中的项目规范(kebab-case、命名导出、导入顺序、
import type、命名常量)
(绝不能在客户端代码中暴露 STRIPE_SECRET_KEY——它只能保留在服务器端)
(必须使用 stripe.webhooks.constructEvent() 验证 webhook 签名,并传入原始请求正文——绝不能传入解析后的 JSON)
(所有会更改数据的(POST)请求都必须使用幂等键,以防止重复扣款)
(必须使用 instanceof Stripe.errors.StripeError 处理所有 Stripe 错误——绝不能忽略支付错误)
(货币金额必须使用最小货币单位表示——美元使用美分,而不是美元整数)
不遵守这些规则会导致安全漏洞、重复扣款和无提示的支付失败。