Back to Airi

Stripe Pricing Architecture

apps/server/docs/ai-context/stripe-pricing.md

0.10.14.8 KB
Original Source

Stripe Pricing Architecture

设计决策

Stripe 是 Flux 充值定价的单一真相源。服务端不再在 Redis 维护 FLUX_PACKAGES,所有 package 信息直接从 Stripe API 获取。

为什么不用 Redis 维护 packages

之前的设计在 Redis ConfigKV 中维护 FLUX_PACKAGES(含 amount、label、price 等),导致:

  • 价格信息在 Stripe 和 Redis 之间重复维护
  • currency 硬编码为 USD,无法支持微信支付(需要 CNY/GBP)
  • 新增/修改 package 需要同时改 Stripe 和 Redis

现在只需在 Stripe Dashboard 操作 Product/Price,服务端自动同步。

数据模型

Stripe 侧

  • Product — 代表 "Flux 充值" 这个商品(一个即可)
  • Price — 代表一个具体的价格方案,每个 Price 包含:
    • unit_amount + currency(如 300 USD = $3)
    • currency_options(可选)— 支持多币种展示,如 cny: { unit_amount: 2200 }
    • metadata.fluxAmount — 购买此 Price 获得的 Flux 数量
    • metadata.recommended — (可选)设为 'true' 时前端会高亮展示为推荐套餐

Product ID 存储在 ConfigKV STRIPE_FLUX_PRODUCT_ID 中(运营配置,非环境变量)。

多币种支持

通过 Stripe Price 的 currency_options 实现。一个 USD Price 可以同时支持 CNY 结算:

  • 前端展示所有可用货币(从 currency_options 自动提取),用户通过 SelectTab 切换
  • 前端 checkout 时传 { stripePriceId, currency } 给服务端
  • 服务端在 Checkout Session 上设 currency 参数,Stripe 自动用对应 currency_options 的金额
  • Stripe Checkout 页面根据货币自动展示兼容的支付方式(如 CNY → 微信支付)

创建带多币种的 Price:

bash
curl https://api.stripe.com/v1/prices \
  -u "$STRIPE_API_KEY:" \
  -d "product=prod_xxx" \
  -d "unit_amount=300" \
  -d "currency=usd" \
  -d "metadata[fluxAmount]=500" \
  -d "currency_options[cny][unit_amount]=2200"

注意:Stripe CLI 的 prices create 对嵌套参数支持不好,currency_options 需要用 curl 直接调 API。

支付方式

STRIPE_PAYMENT_METHODS 在 ConfigKV 中为可选配置:

  • 未设置(推荐):不传 payment_method_types,Stripe 根据 Dashboard 设置和货币自动决定
  • 已设置:覆盖 Stripe 自动选择,如 ["card", "wechat_pay", "alipay"]

如果手动指定了 wechat_pay,还需设 STRIPE_PAYMENT_METHOD_OPTIONS{"wechat_pay":{"client":"web"}}

缓存

Stripe Price 列表通过 Redis 缓存(key: cache:stripe:prices,TTL 5 分钟),所有实例共享。

  • 命中:直接返回缓存的 Price 列表
  • 未命中:调 Stripe API prices.list (含 expand: ['data.currency_options']),按 unit_amount 升序排列后写入缓存
  • Checkout 时如果 priceId 不在缓存中,fallback 到 prices.retrieve 并 invalidate 缓存

API 流程

GET /api/v1/stripe/packages

  1. 从 ConfigKV 读取 STRIPE_FLUX_PRODUCT_ID
  2. 从 Redis 缓存或 Stripe API 获取 active prices
  3. 返回每个 price 的所有可用货币价格:
    json
    {
      "stripePriceId": "price_xxx",
      "label": "500 Flux",
      "defaultCurrency": "usd",
      "currencies": { "usd": "$3.00", "cny": "¥22.00" },
      "recommended": false
    }
    

POST /api/v1/stripe/checkout

  1. 前端发送 { stripePriceId, currency? }
  2. 服务端验证 price 归属和 fluxAmount metadata
  3. 创建 Checkout Session:
    • currency 参数(如有)让 Stripe 用 currency_options 中的金额
    • payment_method_types 根据 ConfigKV 是否配置决定传或不传
  4. Webhook 收到 checkout.session.completed 后从 metadata 读取 fluxAmount 充值

运营操作

新增价格

用 curl 创建带多币种的 Price(Stripe CLI 不支持嵌套参数):

bash
curl https://api.stripe.com/v1/prices \
  -u "$STRIPE_API_KEY:" \
  -d "product=prod_xxx" \
  -d "unit_amount=1200" \
  -d "currency=usd" \
  -d "metadata[fluxAmount]=2000" \
  -d "metadata[recommended]=true" \
  -d "currency_options[cny][unit_amount]=8800"

无需修改代码或 Redis,/packages 端点在缓存过期后自动返回新 Price。

下架价格

在 Stripe Dashboard 将 Price 设为 inactive,缓存过期后 /packages 自动不再返回。

修改 Product ID

bash
redis-cli SET "config:STRIPE_FLUX_PRODUCT_ID" '"prod_new_id"'

手动清缓存(立即生效)

bash
redis-cli DEL "cache:stripe:prices"

ConfigKV 配置清单

Key类型默认说明
STRIPE_FLUX_PRODUCT_IDstring?Stripe Product ID,未设置时 top-up 不可用
STRIPE_PAYMENT_METHODSstring[]?不设则 Stripe 自动决定;设了则覆盖
STRIPE_PAYMENT_METHOD_OPTIONSRecord?{}支付方式选项,如 {"wechat_pay":{"client":"web"}}