software-payments
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePayments & Billing Engineering
支付与计费工程
Use this skill to design, implement, and debug production payment integrations: checkout flows, subscription management, webhook handling, regional pricing, feature gating, one-time purchases, billing portals, and payment testing.
Defaults bias toward: Stripe as primary processor (most common), webhooks as source of truth, idempotent handlers, lazy-initialized clients, dynamic payment methods, Zod validation at boundaries, structured logging, and fire-and-forget for non-critical tracking. For complex billing, consider a billing orchestrator (Chargebee, Recurly, Lago) on top of Stripe/Adyen.
使用此技能设计、实现和调试生产环境的支付集成:结账流程、订阅管理、Webhook处理、区域定价、功能权限控制、一次性购买、计费门户以及支付测试。
默认偏好设置:以Stripe作为主要支付处理器(最常用),以Webhook作为事实数据源,使用幂等处理器、延迟初始化客户端、动态支付方式、边界处的Zod验证、结构化日志,以及非关键跟踪的即发即弃模式。对于复杂计费场景,可考虑在Stripe/Adyen之上使用计费编排器(Chargebee、Recurly、Lago)。
Quick Reference
快速参考
| Task | Default Picks | Notes |
|---|---|---|
| Subscription billing | Stripe Checkout (hosted) | Omit |
| MoR / tax compliance | Stripe Managed Payments / Paddle / LemonSqueezy | MoR handles VAT/sales tax for you |
| Mobile subscriptions | RevenueCat | Wraps App Store + Google Play |
| Enterprise / high-volume | Adyen | 250+ payment methods, interchange++ pricing |
| Complex billing logic | Chargebee / Recurly on top of Stripe | Per-seat + usage, contract billing, revenue recognition |
| Usage-based billing | Stripe Billing Meters or Lago (open-source) | API calls, AI tokens, compute metering |
| UK Direct Debit | GoCardless | Bacs/SEPA/ACH DD, lowest involuntary churn |
| EU multi-method | Mollie | iDEAL, Bancontact, SEPA DD, Klarna — 25+ methods |
| Online + POS | Square | Unified commerce: online payments + in-person readers |
| Bank-to-bank (A2A) | Open Banking (TrueLayer / Yapily) | Zero card fees, instant settlement, no chargebacks |
| Webhook handling | Verify signature + idempotent handlers | Stripe retries for 3 days |
| Feature gating | Tier hierarchy + feature matrix | Check at API boundary |
| One-time purchases | Stripe Checkout | Alongside subscriptions |
| Billing portal | Stripe Customer Portal | Self-service management |
| Regional pricing | PPP-adjusted prices per country | Use |
| PayPal button | Stripe PayPal method or PayPal Commerce Platform | Avoid Braintree — deprecated 2026, EOL Jan 2027 |
| BNPL (e-commerce) | Klarna (via Stripe/Mollie/direct) | Split payments; UK regulation expected 2026-27 |
| Testing | Stripe CLI + test cards | |
| 任务 | 默认选择 | 说明 |
|---|---|---|
| 订阅计费 | Stripe Checkout(托管式) | 省略 |
| 商户责任方(MoR)/税务合规 | Stripe Managed Payments / Paddle / LemonSqueezy | MoR会为您处理增值税/销售税 |
| 移动端订阅 | RevenueCat | 封装App Store + Google Play |
| 企业级/高交易量 | Adyen | 支持250+种支付方式,采用手续费加成定价 |
| 复杂计费逻辑 | 基于Stripe的Chargebee / Recurly | 支持按席位+使用量计费、合同计费、收入确认 |
| 基于使用量的计费 | Stripe Billing Meters 或 Lago(开源) | 适用于API调用、AI令牌、计算计量场景 |
| 英国直接借记 | GoCardless | 支持Bacs/SEPA/ACH直接借记,非自愿流失率最低 |
| 欧盟多支付方式 | Mollie | 支持iDEAL、Bancontact、SEPA直接借记、Klarna等25+种方式 |
| 线上+线下POS | Square | 统一商务:线上支付+线下读卡器 |
| 银行间转账(A2A) | 开放银行(TrueLayer / Yapily) | 无卡费、即时结算、无拒付 |
| Webhook处理 | 验证签名+幂等处理器 | Stripe会重试3天 |
| 功能权限控制 | 层级体系+功能矩阵 | 在API边界处校验 |
| 一次性购买 | Stripe Checkout | 可与订阅功能搭配使用 |
| 计费门户 | Stripe Customer Portal | 自助管理功能 |
| 区域定价 | 基于购买力平价(PPP)的各国定价 | 使用 |
| PayPal按钮 | Stripe PayPal方式或PayPal Commerce Platform | 避免使用Braintree——2026年弃用,2027年1月停止服务 |
| 先买后付(BNPL,电商场景) | Klarna(通过Stripe/Mollie或直接集成) | 支持分期付款;英国预计2026-27年出台相关监管政策 |
| 测试 | Stripe CLI + 测试卡 | 测试卡号: |
Scope
适用范围
Use this skill to:
- Implement checkout flows (hosted, embedded, custom)
- Build subscription lifecycle management (create, upgrade, downgrade, cancel)
- Handle webhooks reliably (signature verification, idempotency, error handling)
- Set up regional/multi-currency pricing (PPP, emerging markets)
- Build feature gating and entitlement systems
- Implement one-time purchases alongside subscriptions
- Create billing portal integrations
- Test payment flows end-to-end
- Debug common payment integration issues
使用此技能可完成:
- 实现结账流程(托管式、嵌入式、自定义)
- 构建订阅生命周期管理(创建、升级、降级、取消)
- 可靠处理Webhook(签名验证、幂等性、错误处理)
- 设置区域/多币种定价(PPP、新兴市场)
- 构建功能权限控制和授权系统
- 实现订阅之外的一次性购买功能
- 创建计费门户集成
- 端到端测试支付流程
- 调试常见支付集成问题
When NOT to Use This Skill
不适用于以下场景
Use a different skill when:
- General backend patterns -> See software-backend
- API design only (no payments) -> See dev-api-design
- Conversion optimization -> See marketing-cro
- Business model / pricing strategy -> See startup-business-models
- Security audits -> See software-security-appsec
在以下场景请使用其他技能:
- 通用后端模式 -> 参考software-backend
- 仅API设计(无支付功能) -> 参考dev-api-design
- 转化率优化 -> 参考marketing-cro
- 商业模式/定价策略 -> 参考startup-business-models
- 安全审计 -> 参考software-security-appsec
Decision Tree: Payment Platform Selection
支付平台选择决策树
Three platform layers (can be combined):
| Layer | Role | Examples |
|---|---|---|
| Payment Processor | Moves money, payment methods, fraud | Stripe, Adyen, Mollie, Square |
| Merchant of Record (MoR) | Handles tax, legal, disputes for you | Paddle, LemonSqueezy, Stripe Managed Payments |
| Billing Orchestrator | Subscription logic, dunning, revenue recognition | Chargebee, Recurly, Lago (open-source) |
| Direct Debit | Bank-account recurring pulls | GoCardless (Bacs, SEPA, ACH) |
| Open Banking (A2A) | Bank-to-bank instant payments | TrueLayer, Yapily |
text
Payment integration needs: [Business Model]
STEP 1: Choose your processor
- Default / most common -> Stripe
- Enterprise, >$1M/yr, 250+ payment methods -> Adyen
- EU-focused, need iDEAL/Bancontact/SEPA -> Mollie
- Need PayPal button -> Stripe (PayPal method) or PayPal Commerce Platform
- WARNING: Do NOT start new projects on Braintree (deprecated 2026, EOL Jan 2027)
STEP 2: Do you need a MoR?
- Handle own tax + compliance -> Skip MoR, use processor directly
- Want tax/VAT/disputes handled -> Stripe Managed Payments, Paddle, LemonSqueezy
- Indie / small SaaS -> LemonSqueezy (simplest MoR)
- EU-heavy customer base -> Paddle (strongest EU VAT handling)
STEP 3: Is billing logic complex?
- Simple tiers (free/pro/enterprise) -> Stripe Billing is sufficient
- Per-seat + usage, contract billing, rev-rec -> Chargebee or Recurly on top of Stripe
- Usage-based (API calls, AI tokens) -> Stripe Billing Meters or Lago (open-source)
- B2C subscriptions, churn focus -> Recurly (strong revenue recovery)
STEP 4: Platform-specific needs
- Mobile app (iOS/Android) -> RevenueCat (wraps both stores)
- Hybrid (web + app) -> RevenueCat + Stripe (share customer IDs)
- Marketplace / multi-party -> Stripe Connect
- UK Direct Debit recurring -> GoCardless (Bacs DD, lowest involuntary churn)
- Multi-method EU checkout -> Mollie (25+ methods, single integration)
- Online + in-person POS -> Square (unified commerce)
- High-value A2A / zero card fees -> Open Banking (TrueLayer)
- BNPL for e-commerce -> Klarna (via Stripe, Mollie, or direct)
- One-time digital goods -> Stripe Checkout (payment mode)
- Physical goods -> Stripe + shipping integration
- Emerging markets / PPP -> Multiple Stripe Price objects per region
- Multi-currency -> Stripe multi-currency or Paddle (auto-converts)
- B2B invoicing -> Stripe InvoicingFor detailed platform comparison tables, see references/platform-comparison.md.
For UK/EU-specific platforms (GoCardless, Mollie, Square, Klarna, Open Banking), see references/uk-eu-payments-guide.md.
分为三个平台层级(可组合使用):
| 层级 | 角色 | 示例 |
|---|---|---|
| 支付处理器 | 处理资金流转、支付方式、欺诈检测 | Stripe, Adyen, Mollie, Square |
| 商户责任方(MoR) | 为您处理税务、法务、纠纷事宜 | Paddle, LemonSqueezy, Stripe Managed Payments |
| 计费编排器 | 处理订阅逻辑、催缴、收入确认 | Chargebee, Recurly, Lago(开源) |
| 直接借记 | 定期从银行账户扣款 | GoCardless(支持Bacs、SEPA、ACH) |
| 开放银行(A2A) | 银行间即时转账 | TrueLayer, Yapily |
text
支付集成需求: [商业模式]
STEP 1: 选择支付处理器
- 默认/最常用 -> Stripe
- 企业级、年交易额超100万美元、需250+支付方式 -> Adyen
- 聚焦欧盟市场、需iDEAL/Bancontact/SEPA -> Mollie
- 需要PayPal按钮 -> Stripe(PayPal方式)或PayPal Commerce Platform
- 警告:不要在新项目中使用Braintree(2026年弃用,2027年1月停止服务)
STEP 2: 是否需要MoR?
- 自行处理税务+合规 -> 跳过MoR,直接使用支付处理器
- 希望税务/增值税/纠纷由第三方处理 -> Stripe Managed Payments, Paddle, LemonSqueezy
- 独立开发者/小型SaaS -> LemonSqueezy(最简单的MoR)
- 客户群体主要在欧盟 -> Paddle(欧盟增值税处理能力最强)
STEP 3: 计费逻辑是否复杂?
- 简单层级(免费/专业/企业) -> Stripe Billing足够满足需求
- 按席位+使用量计费、合同计费、收入确认 -> 基于Stripe的Chargebee或Recurly
- 基于使用量(API调用、AI令牌) -> Stripe Billing Meters或Lago(开源)
- B2C订阅、关注用户留存 -> Recurly(收入恢复能力强)
STEP 4: 特定平台需求
- 移动应用(iOS/Android) -> RevenueCat(封装两大应用商店)
- 混合模式(网页+应用) -> RevenueCat + Stripe(共享客户ID)
- 市场平台/多方参与 -> Stripe Connect
- 英国定期直接借记 -> GoCardless(Bacs直接借记,非自愿流失率最低)
- 欧盟多支付方式结账 -> Mollie(25+种方式,单次集成)
- 线上+线下POS -> Square(统一商务)
- 高价值A2A转账/无卡费 -> 开放银行(TrueLayer)
- 电商先买后付 -> Klarna(通过Stripe、Mollie或直接集成)
- 一次性数字商品 -> Stripe Checkout(payment模式)
- 实体商品 -> Stripe + 物流集成
- 新兴市场/PPP -> 为每个区域创建独立的Stripe价格对象
- 多币种 -> Stripe多币种功能或Paddle(自动转换)
- B2B发票 -> Stripe Invoicing详细的平台对比表请参考references/platform-comparison.md。
针对英国/欧盟特定平台(GoCardless、Mollie、Square、Klarna、开放银行)的指南请参考references/uk-eu-payments-guide.md。
Stripe Integration Patterns (Feb 2026)
Stripe集成模式(2026年2月)
1. Client Initialization
1. 客户端初始化
CRITICAL: Lazy-initialize the Stripe client. Import-time initialization fails during build/SSR when env vars aren't available.
typescript
// CORRECT: Lazy initialization with proxy for backwards compatibility
import Stripe from 'stripe';
let _stripe: Stripe | null = null;
export function getStripeServer(): Stripe {
if (!_stripe) {
const secretKey = process.env.STRIPE_SECRET_KEY;
if (!secretKey) {
throw new Error('STRIPE_SECRET_KEY is not configured');
}
_stripe = new Stripe(secretKey, {
apiVersion: '2026-01-28.clover', // Pin to specific version
typescript: true,
});
}
return _stripe;
}
// Proxy for convenience (backwards-compatible named export)
export const stripe = {
get customers() { return getStripeServer().customers; },
get subscriptions() { return getStripeServer().subscriptions; },
get checkout() { return getStripeServer().checkout; },
get billingPortal() { return getStripeServer().billingPortal; },
get webhooks() { return getStripeServer().webhooks; },
};typescript
// WRONG: Crashes during build when STRIPE_SECRET_KEY is undefined
import Stripe from 'stripe';
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); // Build failure关键:延迟初始化Stripe客户端。 在构建/SSR阶段环境变量不可用时,导入时初始化会失败。
typescript
// CORRECT: 延迟初始化+代理以实现向后兼容
import Stripe from 'stripe';
let _stripe: Stripe | null = null;
export function getStripeServer(): Stripe {
if (!_stripe) {
const secretKey = process.env.STRIPE_SECRET_KEY;
if (!secretKey) {
throw new Error('STRIPE_SECRET_KEY is not configured');
}
_stripe = new Stripe(secretKey, {
apiVersion: '2026-01-28.clover', // 固定到特定版本
typescript: true,
});
}
return _stripe;
}
// 便捷代理(向后兼容的命名导出)
export const stripe = {
get customers() { return getStripeServer().customers; },
get subscriptions() { return getStripeServer().subscriptions; },
get checkout() { return getStripeServer().checkout; },
get billingPortal() { return getStripeServer().billingPortal; },
get webhooks() { return getStripeServer().webhooks; },
};typescript
// WRONG: 当STRIPE_SECRET_KEY未定义时构建失败
import Stripe from 'stripe';
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); // Build failure2. Checkout Session Creation
2. 结账会话创建
CRITICAL: Do NOT set . Omitting it enables Stripe's dynamic payment method selection (Apple Pay, Google Pay, Link, bank transfers, local methods) based on customer region and device.
payment_method_typestypescript
const session = await stripe.checkout.sessions.create({
customer: customerId,
mode: 'subscription',
// DO NOT set payment_method_types — let Stripe auto-select
line_items: [{ price: priceId, quantity: 1 }],
subscription_data: {
trial_period_days: 7,
metadata: {
user_id: userId,
billing_interval: interval,
},
},
success_url: `${appUrl}/dashboard?checkout=success&tier=${tier}`,
cancel_url: `${appUrl}/dashboard?checkout=canceled`,
allow_promotion_codes: true,
billing_address_collection: 'auto',
metadata: {
user_id: userId,
tier,
billing_interval: interval,
},
});typescript
// WRONG: Limits to cards only, blocks Apple Pay, Google Pay, Link, etc.
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'], // REMOVE THIS
// ...
});关键:不要设置。 省略该字段可启用Stripe的动态支付方式选择(Apple Pay、Google Pay、Link、银行转账、本地支付方式),具体取决于客户所在区域和设备。
payment_method_typestypescript
const session = await stripe.checkout.sessions.create({
customer: customerId,
mode: 'subscription',
// DO NOT set payment_method_types — 让Stripe自动选择
line_items: [{ price: priceId, quantity: 1 }],
subscription_data: {
trial_period_days: 7,
metadata: {
user_id: userId,
billing_interval: interval,
},
},
success_url: `${appUrl}/dashboard?checkout=success&tier=${tier}`,
cancel_url: `${appUrl}/dashboard?checkout=canceled`,
allow_promotion_codes: true,
billing_address_collection: 'auto',
metadata: {
user_id: userId,
tier,
billing_interval: interval,
},
});typescript
// WRONG: 仅支持银行卡,阻止Apple Pay、Google Pay、Link等方式
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'], // REMOVE THIS
// ...
});3. Webhook Handler Architecture
3. Webhook处理器架构
Webhooks are the source of truth for subscription state. Never trust client-side callbacks alone.
Pattern: read raw body as text → verify → → return on success or 500 on handler error (so Stripe retries). Full route implementation in references/stripe-patterns.md.
stripe.webhooks.constructEvent(body, signature, secret)switch(event.type){ received: true }Webhook是订阅状态的事实数据源。 永远不要单独信任客户端回调。
模式:将原始正文读取为文本 → 使用验证签名 → 处理事件 → 成功时返回,处理器出错时返回500(以便Stripe重试)。完整路由实现请参考references/stripe-patterns.md。
stripe.webhooks.constructEvent(body, signature, secret)switch(event.type){ received: true }Essential Webhook Events
核心Webhook事件
| Event | When | Handler Pattern |
|---|---|---|
| Checkout finishes | Link Stripe customer to user, create subscription record |
| Abandoned checkout | Fire-and-forget analytics (never fail the response) |
| New subscription | Upsert subscription record with tier, status, period |
| Plan change, renewal, cancel-at-period-end | Update tier, status, cancel flags |
| Subscription ends | Reset to free tier |
| Successful charge | Update period dates, process referral rewards |
| Failed charge | Set status to |
| 3 days before trial ends | Trigger retention email |
| 事件 | 触发时机 | 处理器模式 |
|---|---|---|
| 结账完成 | 将Stripe客户与用户关联,创建订阅记录 |
| 结账被放弃 | 即发即弃式分析(永远不要让响应失败) |
| 创建新订阅 | 插入或更新订阅记录,包含层级、状态、周期 |
| 套餐变更、续费、到期取消 | 更新层级、状态、取消标记 |
| 订阅结束 | 重置为免费层级 |
| 扣费成功 | 更新周期日期,处理推荐奖励 |
| 扣费失败 | 将状态设置为 |
| 试用结束前3天 | 触发留存邮件 |
Fire-and-Forget Pattern for Non-Critical Tracking
非关键跟踪的即发即弃模式
For (and similar analytics events): call tracking without , never . Non-critical tracking must not cause a webhook 500.
checkout.session.expiredawaitthrow对于(及类似分析事件):调用跟踪接口时不要使用,永远不要抛出异常。非关键跟踪一定不能导致Webhook返回500。
checkout.session.expiredawait4. Subscription Tier Model
4. 订阅层级模型
typescript
// Type definitions
export type SubscriptionTier = 'free' | 'starter' | 'pro' | 'enterprise';
export type SubscriptionStatus = 'active' | 'trialing' | 'canceled' | 'past_due' | 'incomplete';
export type BillingInterval = 'month' | 'year';
// Tier hierarchy for comparison
export const TIER_HIERARCHY: Record<SubscriptionTier, number> = {
free: 0,
starter: 1,
pro: 2,
enterprise: 3,
};
// Feature access matrix
export type Feature = 'basic_dashboard' | 'advanced_reports' | 'api_access' | 'priority_support';
const TIER_FEATURES: Record<SubscriptionTier, Feature[]> = {
free: ['basic_dashboard'],
starter: ['basic_dashboard', 'advanced_reports'],
pro: ['basic_dashboard', 'advanced_reports', 'api_access'],
enterprise: ['basic_dashboard', 'advanced_reports', 'api_access', 'priority_support'],
};
export function hasFeatureAccess(tier: SubscriptionTier, feature: Feature): boolean {
return TIER_FEATURES[tier].includes(feature);
}
export function isTierUpgrade(current: SubscriptionTier, target: SubscriptionTier): boolean {
return (TIER_HIERARCHY[target] ?? 0) > (TIER_HIERARCHY[current] ?? 0);
}typescript
// 类型定义
export type SubscriptionTier = 'free' | 'starter' | 'pro' | 'enterprise';
export type SubscriptionStatus = 'active' | 'trialing' | 'canceled' | 'past_due' | 'incomplete';
export type BillingInterval = 'month' | 'year';
// 用于比较的层级体系
export const TIER_HIERARCHY: Record<SubscriptionTier, number> = {
free: 0,
starter: 1,
pro: 2,
enterprise: 3,
};
// 功能访问矩阵
export type Feature = 'basic_dashboard' | 'advanced_reports' | 'api_access' | 'priority_support';
const TIER_FEATURES: Record<SubscriptionTier, Feature[]> = {
free: ['basic_dashboard'],
starter: ['basic_dashboard', 'advanced_reports'],
pro: ['basic_dashboard', 'advanced_reports', 'api_access'],
enterprise: ['basic_dashboard', 'advanced_reports', 'api_access', 'priority_support'],
};
export function hasFeatureAccess(tier: SubscriptionTier, feature: Feature): boolean {
return TIER_FEATURES[tier].includes(feature);
}
export function isTierUpgrade(current: SubscriptionTier, target: SubscriptionTier): boolean {
return (TIER_HIERARCHY[target] ?? 0) > (TIER_HIERARCHY[current] ?? 0);
}5. Upgrade/Downgrade Flow
5. 升级/降级流程
Use with and the new on the existing item. Update local DB immediately; webhook will confirm. See full lifecycle in references/subscription-lifecycle.md.
stripe.subscriptions.update()proration_behavior: 'create_prorations'price使用,设置并为现有项目指定新。立即更新本地数据库;Webhook会确认变更。完整生命周期请参考references/subscription-lifecycle.md。
stripe.subscriptions.update()proration_behavior: 'create_prorations'price6. Regional / PPP Pricing
6. 区域/PPP定价
Create separate Stripe Price objects per region (standard vs emerging). Use or GeoIP for detection. Full implementation and market list in references/regional-pricing-guide.md.
x-vercel-ip-country为每个区域(标准市场 vs 新兴市场)创建独立的Stripe价格对象。使用或GeoIP进行检测。完整实现和市场列表请参考references/regional-pricing-guide.md。
x-vercel-ip-country7. One-Time Purchases Alongside Subscriptions
7. 订阅之外的一次性购买
typescript
// Some products are one-time (e.g., PDF reports, credits)
// but subscribers get unlimited access
export function hasUnlimitedProductAccess(
tier: SubscriptionTier,
status: SubscriptionStatus,
product: OneTimeProduct
): boolean {
const isActive = status === 'active' || status === 'trialing';
if (!isActive) return false;
const productConfig = ONE_TIME_PRODUCTS[product];
if (!productConfig.unlimitedFeature) return false;
return hasFeatureAccess(tier, productConfig.unlimitedFeature);
}typescript
// 部分产品为一次性购买(如PDF报告、积分)
// 但订阅用户可无限访问
export function hasUnlimitedProductAccess(
tier: SubscriptionTier,
status: SubscriptionStatus,
product: OneTimeProduct
): boolean {
const isActive = status === 'active' || status === 'trialing';
if (!isActive) return false;
const productConfig = ONE_TIME_PRODUCTS[product];
if (!productConfig.unlimitedFeature) return false;
return hasFeatureAccess(tier, productConfig.unlimitedFeature);
}8. Billing Portal
8. 计费门户
Use to redirect customers to Stripe's self-service portal for plan changes, payment method updates, and cancellation. See references/stripe-patterns.md for portal configuration checklist.
stripe.billingPortal.sessions.create()使用将客户重定向到Stripe的自助门户,进行套餐变更、支付方式更新和取消订阅操作。门户配置清单请参考references/stripe-patterns.md。
stripe.billingPortal.sessions.create()9. Referral/Coupon Integration
9. 推荐/优惠券集成
Key constraint: and are mutually exclusive in Stripe Checkout. If a referral coupon applies, set and omit . On with , reward the referrer via .
allow_promotion_codesdiscountsdiscounts: [{ coupon: REFERRAL_COUPON_ID }]allow_promotion_codesinvoice.payment_succeededbilling_reason === 'subscription_create'stripe.customers.createBalanceTransaction()关键约束:Stripe Checkout中和互斥。如果适用推荐优惠券,请设置并省略。当且时,通过奖励推荐人。
allow_promotion_codesdiscountsdiscounts: [{ coupon: REFERRAL_COUPON_ID }]allow_promotion_codesinvoice.payment_succeededbilling_reason === 'subscription_create'stripe.customers.createBalanceTransaction()Feature Gating Patterns
功能权限控制模式
Every paid feature requires enforcement at 3 layers: Feature Registry (maps features to tiers), API Enforcement (returns 403), UI Paywall (shows upgrade CTA). Missing any layer creates a security hole or broken UX.
Key anti-patterns:
- Gate on Wrong Key: If the feature key is in the free tier, the gate is a permanent no-op.
- Polymorphic Field Shapes: crashes
transits: Transit[] | { __gated: true }. Use consistent shapes with an explicit(data.transits || []).sort()flag.transitsGated: boolean - Checkout Mutual Exclusivity: +
allow_promotion_codestogether = Stripe rejects.discounts
Always verify Stripe SDK TypeScript types (), not documentation examples.
node_modules/stripe/types/For detailed gating architecture (consumables, fraud prevention, discriminated unions), see references/feature-gating-patterns.md.
每个付费功能需要在三个层级进行校验:功能注册表(将功能映射到层级)、API校验(返回403)、UI付费墙(显示升级号召)。缺少任何一层都会造成安全漏洞或糟糕的用户体验。
常见反模式:
- 错误的校验键:如果功能键属于免费层级,校验将永久无效。
- 多态字段结构:会导致
transits: Transit[] | { __gated: true }崩溃。使用一致的结构,添加明确的(data.transits || []).sort()标记。transitsGated: boolean - 结账互斥问题:同时设置+
allow_promotion_codes会被Stripe拒绝。discounts
务必验证Stripe SDK的TypeScript类型(),而不是文档示例。
node_modules/stripe/types/详细的权限控制架构(消耗品、欺诈预防、区分联合类型)请参考references/feature-gating-patterns.md。
Stripe API Version Notes
Stripe API版本说明
Current version: . Key breaking change: replaced by since . Full version table and migration code in references/stripe-patterns.md.
2026-01-28.cloverinvoice.subscriptioninvoice.parent.subscription_details2025-11-17.clover当前版本:。关键破坏性变更:自版本起,被替代。完整版本表和迁移代码请参考references/stripe-patterns.md。
2026-01-28.clover2025-11-17.cloverinvoice.subscriptioninvoice.parent.subscription_detailsCommon Mistakes and Anti-Patterns
常见错误与反模式
| FAIL Avoid | PASS Instead | Why |
|---|---|---|
| Omit the field entirely | Blocks Apple Pay, Google Pay, Link, local methods |
| Trusting client-side checkout callback | Use webhooks as source of truth | Client can close browser before callback |
| Lazy-initialize in a function | Build fails when env var is undefined |
| Catching webhook errors silently | Log + return 500 so Stripe retries | Lost events = lost revenue |
| Storing subscription state only client-side | Sync from webhook to DB | Single source of truth |
| Hardcoding prices in code | Use Stripe Price objects via env vars | Prices change, regional variants |
| Skipping webhook signature verification | Always verify with | Prevents replay/spoofing attacks |
Using | Use | Breaking change since 2025-11-17.clover |
| Don't await, don't throw | Non-critical tracking must not fail webhooks |
Missing UUID validation on | Validate with regex before DB operations | Prevents injection and corrupt data |
| Creating checkout without checking existing subscription | Check and use upgrade flow if active | Prevents duplicate subscriptions |
Using | Use Stripe CLI: | Real signature verification in dev |
| 错误做法 | 正确做法 | 原因 |
|---|---|---|
| 完全省略该字段 | 会阻止Apple Pay、Google Pay、Link、本地支付方式 |
| 信任客户端结账回调 | 使用Webhook作为事实数据源 | 客户端可能在回调前关闭浏览器 |
在模块顶层执行 | 在函数中延迟初始化 | 环境变量未定义时构建失败 |
| 静默捕获Webhook错误 | 记录日志+返回500以便Stripe重试 | 丢失事件会导致收入损失 |
| 仅在客户端存储订阅状态 | 通过Webhook同步到数据库 | 确保单一事实数据源 |
| 在代码中硬编码价格 | 通过环境变量使用Stripe价格对象 | 价格会变化,且存在区域变体 |
| 跳过Webhook签名验证 | 始终使用 | 防止重放/伪造攻击 |
使用 | 使用 | 自2025-11-17.clover版本起的破坏性变更 |
对即发即弃式分析使用 | 不使用await,不抛出异常 | 非关键跟踪不能导致Webhook失败 |
不对元数据中的 | 在数据库操作前用正则验证 | 防止注入和数据损坏 |
| 不检查现有订阅就创建结账会话 | 检查并在订阅活跃时使用升级流程 | 防止重复订阅 |
使用 | 使用Stripe CLI: | 在开发环境中进行真实的签名验证 |
E2E Testing Patterns
端到端测试模式
Quick reference — full patterns in references/testing-patterns.md.
bash
undefined快速参考——完整模式请参考references/testing-patterns.md。
bash
undefinedStripe CLI: forward events to local webhook endpoint
Stripe CLI:将事件转发到本地Webhook端点
stripe listen --forward-to localhost:3001/api/stripe/webhook
stripe listen --forward-to localhost:3001/api/stripe/webhook
Trigger specific events
触发特定事件
stripe trigger checkout.session.completed
stripe trigger invoice.payment_failed
| Card | Scenario |
|------|----------|
| `4242 4242 4242 4242` | Successful payment |
| `4000 0000 0000 0002` | Declined |
| `4000 0000 0000 3220` | 3D Secure required |
| `4000 0000 0000 9995` | Insufficient funds |
---stripe trigger checkout.session.completed
stripe trigger invoice.payment_failed
| 测试卡号 | 场景 |
|------|----------|
| `4242 4242 4242 4242` | 支付成功 |
| `4000 0000 0000 0002` | 支付被拒绝 |
| `4000 0000 0000 3220` | 需要3D安全验证 |
| `4000 0000 0000 9995` | 余额不足 |
---Checkout Contract Propagation
结账契约传播
When checkout API response contracts change, treat it as a cross-surface migration. Enumerate all entrypoints, update every caller, route blocked flows to one shared recovery UX. Full checklist in references/in-app-browser-checkout-contract.md and assets/template-checkout-entrypoint-propagation-checklist.md.
当结账API响应契约变更时,需将其视为跨端迁移。枚举所有入口点,更新每个调用方,将阻塞的路由引导至统一的恢复用户体验。完整清单请参考references/in-app-browser-checkout-contract.md和assets/template-checkout-entrypoint-propagation-checklist.md。
Security Checklist
安全清单
10-point checklist covering webhook signature verification, secrets management, UUID validation, HTTPS, idempotency, and rate limiting. Full checklist in references/stripe-patterns.md.
包含10项检查,覆盖Webhook签名验证、密钥管理、UUID验证、HTTPS、幂等性和速率限制。完整清单请参考references/stripe-patterns.md。
Navigation
导航
References
- references/stripe-patterns.md - Stripe patterns: webhook handlers, idempotency, status mapping, error handling, dunning, usage-based billing, security checklist, API version notes
- references/platform-comparison.md - Platform comparison: Stripe, Adyen, Paddle, LemonSqueezy, Chargebee, Recurly, Lago, Braintree (deprecated)
- references/uk-eu-payments-guide.md - UK/EU platforms: GoCardless, Mollie, Square, PayPal Commerce, Klarna, Open Banking (TrueLayer, Yapily)
- references/testing-patterns.md - E2E testing: Stripe CLI, Playwright checkout, test cards, state sync
- references/subscription-lifecycle.md - Full subscription state machine, trials, upgrades/downgrades, cancellation, dunning, pause/resume, database schema
- references/regional-pricing-guide.md - PPP implementation, multi-currency Stripe prices, tax by region, fraud prevention, A/B testing pricing
- references/webhook-reliability-patterns.md - Idempotency, retry handling, dead letter queues, monitoring, event ordering, queue-based processing
- references/feature-gating-patterns.md - Feature gating: consumable vs binary unlocks, spread-then-override filtering, fraud prevention, discriminated union typed responses
- references/in-app-browser-checkout-contract.md - Checkout response contract propagation for in-app browser recovery and cross-surface consistency
- references/ops-runbook-checkout-errors.md - Checkout 500 debugging: RLS denials, auth policy, incident loop
- data/sources.json - External documentation links (69 sources)
Templates
- assets/template-checkout-entrypoint-propagation-checklist.md - Migration checklist for contract changes across all checkout callers
Related Skills
- ../software-backend/SKILL.md - Backend API patterns, database, auth
- ../dev-api-design/SKILL.md - API design patterns
- ../marketing-cro/SKILL.md - Conversion optimization for checkout
- ../startup-business-models/SKILL.md - Pricing strategy
- ../software-security-appsec/SKILL.md - Payment security
- ../qa-testing-playwright/SKILL.md - E2E testing patterns
参考文档
- references/stripe-patterns.md - Stripe模式:Webhook处理器、幂等性、状态映射、错误处理、催缴、基于使用量的计费、安全清单、API版本说明
- references/platform-comparison.md - 平台对比:Stripe、Adyen、Paddle、LemonSqueezy、Chargebee、Recurly、Lago、Braintree(已弃用)
- references/uk-eu-payments-guide.md - 英国/欧盟平台:GoCardless、Mollie、Square、PayPal Commerce、Klarna、开放银行(TrueLayer、Yapily)
- references/testing-patterns.md - 端到端测试:Stripe CLI、Playwright结账测试、测试卡、状态同步
- references/subscription-lifecycle.md - 完整订阅状态机、试用、升级/降级、取消、催缴、暂停/恢复、数据库 schema
- references/regional-pricing-guide.md - PPP实现、Stripe多币种价格、区域税务、欺诈预防、定价A/B测试
- references/webhook-reliability-patterns.md - 幂等性、重试处理、死信队列、监控、事件排序、基于队列的处理
- references/feature-gating-patterns.md - 功能权限控制:消耗品 vs 二进制解锁、扩散-覆盖过滤、欺诈预防、区分联合类型响应
- references/in-app-browser-checkout-contract.md - 应用内浏览器结账的契约传播,确保恢复体验和跨端一致性
- references/ops-runbook-checkout-errors.md - 结账500错误调试:RLS拒绝、授权策略、事件循环
- data/sources.json - 外部文档链接(69个来源)
模板
- assets/template-checkout-entrypoint-propagation-checklist.md - 跨所有结账调用方的契约变更迁移清单
相关技能
- ../software-backend/SKILL.md - 后端API模式、数据库、认证
- ../dev-api-design/SKILL.md - API设计模式
- ../marketing-cro/SKILL.md - 结账转化率优化
- ../startup-business-models/SKILL.md - 定价策略
- ../software-security-appsec/SKILL.md - 支付安全
- ../qa-testing-playwright/SKILL.md - 端到端测试模式
Freshness Protocol
时效性检查规则
When users ask version-sensitive questions about payment platforms, do a freshness check.
当用户询问支付平台的版本敏感问题时,需进行时效性检查。
Trigger Conditions
触发条件
- "What's the best payment platform for [use case]?"
- "Stripe vs Paddle vs LemonSqueezy?"
- "How do I handle [tax/VAT/sales tax]?"
- "What's new in Stripe [API/Billing/Checkout]?"
- "Is Stripe Managed Payments available?"
- "Best mobile subscription SDK?"
- "[场景]下最佳的支付平台是什么?"
- "Stripe vs Paddle vs LemonSqueezy?"
- "如何处理[税务/增值税/销售税]?"
- "Stripe [API/Billing/Checkout]有什么新功能?"
- "Stripe Managed Payments可用吗?"
- "最佳移动端订阅SDK是什么?"
How to Freshness-Check
时效性检查方法
- Start from (official docs, changelogs, API versions).
data/sources.json - Run a targeted web search for the specific platform and feature.
- Prefer official documentation and changelogs over blog posts.
- 从开始(官方文档、更新日志、API版本)。
data/sources.json - 针对特定平台和功能进行定向网络搜索。
- 优先选择官方文档和更新日志,而非博客文章。
What to Report
需报告的内容
- Current landscape: what is stable and widely used now
- Emerging trends: Managed Payments, usage-based billing, entitlements API, Open Banking
- Deprecated/declining: hardcoded payment_method_types, top-level invoice.subscription, Braintree
- Recommendation: default choice + alternatives with trade-offs
- 当前现状:目前稳定且广泛使用的方案
- 新兴趋势:Managed Payments、基于使用量的计费、授权API、开放银行
- 已弃用/衰退的方案:硬编码payment_method_types、顶层invoice.subscription、Braintree
- 推荐方案:默认选择+带有权衡的替代方案
Ops Runbook
运维手册
For checkout 500 errors with RLS/authorization denials: 5-step incident loop, required logging fields, and guardrails. See references/ops-runbook-checkout-errors.md.
针对带有RLS/授权拒绝的结账500错误:5步事件处理流程、必填日志字段和防护措施。请参考references/ops-runbook-checkout-errors.md。
Fact-Checking
事实核查
- Use web search/web fetch to verify current external facts, versions, pricing, deadlines, regulations, or platform behavior before final answers.
- Prefer primary sources; report source links and dates for volatile information.
- If web access is unavailable, state the limitation and mark guidance as unverified.
- 在给出最终答案前,使用网络搜索/网页抓取验证当前外部事实、版本、定价、截止日期、法规或平台行为。
- 优先选择一手来源;对于易变信息,报告来源链接和日期。
- 如果无法访问网络,说明限制并标记指南为未验证。