跳转到主要内容

Documentation Index

Fetch the complete documentation index at: https://docs.fim.ai/llms.txt

Use this file to discover all available pages before exploring further.

FIM One 在管理员控制的功能标志后面提供完整的 Stripe 计费管道。不需要支付功能的私有部署可以将其关闭,永远不会看到相关 UI。SaaS 运营商只需切换一个开关,即可获得托管结账、客户门户、由 webhook 驱动的订阅生命周期管理和配额强制执行。
计费默认禁用。全新安装和现有自托管部署都以 system_settings.billing_enabled = FALSE 开始。在管理员明确激活之前,不会显示任何计费 UI。

您将获得

  • 免费版和专业版 配有月度令牌配额(默认值:免费版 1M / 专业版 5M;激活后可调整)
  • Stripe 托管结账 — 用户无需您的代码接触卡数据即可升级
  • 客户门户 — 用户可更新支付方式、下载发票、取消订阅——全部在 Stripe 的界面上完成
  • Webhook 驱动的生命周期 — 订阅自动配置和续期;已取消的订阅在周期结束时降级为免费版
  • 配额强制执行 — 按周期跟踪令牌使用情况;中途截断并显示结构化升级提示
  • 管理页面 用于计划 CRUD 和订阅监控

前置条件

  1. Stripe账户已启用实时模式。新加坡注册公司必须完成KYC(营业执照、董事身份证、银行账户)。审批通常需要1-3天。
  2. Stripe实时API密钥,类型为受限制(推荐使用,相比标准sk_live_***更易撤销、权限范围更小)。
  3. Webhook端点可公开访问,地址为<your-domain>/api/webhooks/stripe
  4. 银行账户用于支付。建议多币种结算(例如USD支付到USD账户),以避免非USD默认Stripe账户每笔交易产生1.5-2%的汇兑损失。

设置

1. Stripe 仪表板

创建Pro产品

  1. Catalog → Products → + Add product
  2. Name: Pro, description: 5M tokens / month, priority support
  3. Pricing: Recurring, monthly, $20.00 USD (根据您的定价策略调整)
  4. Save → 复制生成的 price_*** ID(激活后,您将使用此值更新本地 billing_plans 表)

创建受限API密钥

  1. Developers → API keys → + Create restricted key
  2. Name: fim-one production
  3. Permissions (minimum):
    • Customers: Write
    • Subscriptions: Write
    • Checkout Sessions: Write
    • Customer portal: Write
    • Prices: Read
    • Products: Read
  4. Save → copy rk_live_***

注册webhook端点

  1. Developers → Webhooks → + Add endpoint
  2. URL: https://<your-domain>/api/webhooks/stripe
  3. 要接收的事件:
    • checkout.session.completed
    • customer.subscription.created
    • customer.subscription.updated
    • customer.subscription.deleted
    • invoice.payment_succeeded
    • invoice.payment_failed
  4. 保存后,点击”Reveal signing secret”→ 复制 whsec_***

配置多币种结算(推荐)

如果您的Stripe账户默认币种与您收费的价格币种不同(常见情况:SGD账户收取USD费用):
  1. Settings → Bank accounts and currencies → Add a settlement currency
  2. 选择价格币种(例如USD)
  3. 关联匹配的银行账户(例如Aspire USD虚拟账户)
  4. 保存——Stripe将USD费用直接路由到USD支付,无需外汇转换

2. 后端 .env

在生产环境的 .env 中设置这三个密钥:
STRIPE_SECRET_KEY=rk_live_***
STRIPE_WEBHOOK_SECRET=whsec_***
STRIPE_BILLING_RETURN_URL=https://<your-domain>/settings?tab=billing
完整参考请见环境变量 编辑 .env 后重启后端以使密钥生效:
./deploy.sh   # or: docker compose restart fim-one

3. 在管理员中激活

  1. 以管理员身份登录
  2. 管理员 → 系统设置 → 计费
  3. 切换启用 Stripe 计费为 ON
  4. 后端验证 STRIPE_SECRET_KEYSTRIPE_WEBHOOK_SECRET 都存在——如果任一缺失,返回 400 并且切换保持 OFF
  5. 仅在首次激活时,后端运行幂等设置
    • 种子化免费版和专业版套餐(如果已存在则跳过)
    • 设置 system_settings.default_plan_id 为免费版套餐 id
    • 为任何没有套餐的用户回填 users.plan_id = free.id
    • 同步 default_token_quota → 免费版套餐 monthly_token_quota,使现有的管理员控制的全局配额得以保留
  6. 后续的切换关闭/打开是纯标志翻转,无数据副作用

4. 使用您的实时价格更新Pro套餐

激活后,更新预设的Pro套餐以指向您的实时Stripe价格:
  • Admin → Billing → Plans → Pro → Edit
  • 将您的price_1***(来自第1步)粘贴到Stripe Price ID
  • 保存
或通过SQL(如果您更喜欢直接数据库访问):
UPDATE billing_plans
SET stripe_price_id = 'price_1***'
WHERE slug = 'pro';

5. 烟雾测试

  1. 以普通用户身份打开 /settings?tab=billing
  2. 点击升级到 Pro
  3. Stripe Checkout 打开;使用低额真实卡片完成支付(之后退款)
  4. Webhook 应该触发——在 Stripe Dashboard → Webhooks → 最近事件中验证显示 2xx 响应
  5. 订阅行出现在 subscriptions 表中;users.plan_id 切换为 pro
  6. UI 现在显示 Pro 计划 + “管理订阅”按钮

禁用账单

在管理员 → 系统设置 → 账单中,将启用 Stripe 账单开关切换为关闭。 禁用后:
  • 所有 /api/billing/* 端点返回 503
  • Webhook 端点返回 503(Stripe 将重试,然后在仪表板中显示为失败——这是正常的,如果账单永久关闭,你可以改为在 Stripe 仪表板中禁用 Webhook)
  • Plan & Billing 用户界面标签页消失
  • 管理员 → 账单导航组被隐藏
  • 配额链跳过计划层级,直接回退到 default_token_quota
数据被保留:现有的 subscriptionsbilling_plansusers.plan_id 行保持不变。重新启用将从相同状态恢复,无需迁移。

计算参考——配额和令牌数学

这是权威参考,用于决定用户被允许消费的内容、计数器何时重置以及解析链如何组合的每条数值规则。在更改定价、调整配额、构建使用情况仪表板或规划v2/v3工作之前,请阅读本文档。尚未发布的未来规则记录在其保留位置,以便贡献者知道新逻辑在何处插入。

词汇表

变量存储语义范围
users.token_quota按用户(覆盖)三态覆盖;见下文语义NULL0 或正整数
users.tokens_used_this_period按用户(计数器)自上次重置以来的累计令牌非负整数
users.quota_reset_at按用户(锚点)镜像付费用户的 Subscription.current_period_end时间戳
users.plan_id按用户(FK)活跃计划FK billing_plans.id
billing_plans.monthly_token_quota按计划该计划用户的硬上限非负整数
system_settings.default_token_quota单例当无计划适用时的防御性回退非负整数
system_settings.default_plan_id单例新用户/未分配用户的免费计划指针FK 或 NULL
system_settings.billing_enabled单例主开关——控制链的第 2 步布尔值

什么算作一个令牌

令牌消耗在LLM调用层进行计算,来自LiteLLM在每次完成时的usage对象。
  • 计算:每次模型调用的提示令牌 + 完成令牌
  • 计算:多步骤/工具使用智能体流中的每个往返(每次模型调用都是单独的扣费)
  • 计算:嵌入请求(知识库摄取、检索评分)
  • 不计算:输入已暂存但从未发送到模型的内容(例如用户丢弃的已上传文件)
  • 不计算:在到达提供商之前失败的请求(身份验证错误、速率限制预检查)
  • 缓存输入:在v1中按全价计算(不显示提供商缓存折扣)。v2可能会单独计入缓存提示令牌。

三态覆盖语义

users.token_quota 是按用户的管理覆盖。它在一列中承载三种含义:
含义用例
NULL未设置——遵循套餐/默认值所有普通用户的默认状态
0无限制管理员/内部账户;“VIP礼赠”
N > 0硬限制为 N在不取消付费订阅的情况下阻止滥用者;预付企业配额
覆盖始终优先于套餐和默认值。它的存在使管理员能够将单个用户固定在其套餐层级之上或之下,而无需接触Stripe。

配额解析链——v1(当前版本)

对于任何已认证的请求,上限按自上而下的方式计算——首次匹配获胜
1. users.token_quota        ── NULL? skip. 0? unlimited. N>0? cap at N.
2. users.plan.monthly_token_quota   ── only when billing_enabled = TRUE
3. system_settings.default_token_quota  ── defensive fallback
4. unlimited                ── last resort if everything above is NULL
当启用计费时,第3步很少被执行,因为激活会为每个用户回填users.plan_id。它作为纵深防御存在,以确保配置错误的计划永远不会静默地为用户解除上限。

周期重置

  • 对于付费用户,quota_reset_at 镜像 Subscription.current_period_endinvoice.payment_succeeded webhook 处理程序在每次成功续期时将 tokens_used_this_period 设置为 0,并将 quota_reset_at 推进到新周期结束。
  • 对于免费用户(无 Stripe 订阅),每小时 cron 任务在以计划分配日期为锚点的日历月边界处将 tokens_used_this_period 重置为 0。
  • 周期中途的计划变更不会重置计数器——仅续期会重置。这可防止配额循环利用漏洞(“订阅 → 使用专业版配额 → 取消 → 重新订阅”)。

中流强制执行

  • 聊天调用入口的预检查:最便宜的路径,阻止用户无法承担的请求。
  • 流式传输期间,运行中的令牌计数在每个分块上重新评估。超过上限会关闭流,返回结构化终止帧,而不是网络错误。
  • 前端解释终止帧并显示 <QuotaExceededDialog>,其中包含指向 /settings?tab=billing 的深层链接。
  • 非流式响应返回 HTTP 402,响应体为 { code: "QUOTA_EXCEEDED", reset_at, upgrade_url }

账单禁用回退

system_settings.billing_enabled = FALSE 时:
  • 跳过链的第 2 步——链折叠为 override → default → unlimited
  • /api/billing/*/api/webhooks/stripe 返回 503
  • Plan & Billing 用户标签页和 Admin → Billing 导航组被隐藏。
  • 所有账单数据(订阅、套餐、users.plan_id)被保留——重新启用时从相同状态恢复,无需迁移。

保留:配额链 v2 — 团队座位

尚未发布。此处记录以便 v2 工作有已知的落地点。
当团队计划发布时:
  • Subscription.quantity 携带座位数(Stripe 原生)。
  • 用户的有效计划通过团队成员身份解析,然后回退到其个人计划:
    effective_plan = team.plan if team_member(user) else user.plan
    
  • 配额是按座位(每个团队成员获得完整的 monthly_token_quota),而不是共享池。共享池会导致先到先得的耗尽,对客户不利。
  • 覆盖语义保持不变——团队管理员仍然可以通过 users.token_quota = N 对单个成员进行硬限制,该限制在链中位于团队计划之上。

Reserved: quota chain v3 — native Org allocation (no Stripe)

Not yet shipped. Reserved for on-prem / enterprise deployments that allocate quota internally without paying Stripe per user.
  • New table org_quota_allocations(user_id, monthly_token_quota, org_id) distributes a parent budget across members.
  • Allocations are per user, not a shared pool — every member has a clear individual SLA.
  • Updated chain:
    override → max(plan_quota, org_allocation) → default → unlimited
    
  • max(),而非 sum()。付费Pro用户永远不会获得少于他们已支付的配额,即使他们的组织管理员设置了较低的分配。Stripe支付的配额是神圣的。

预留:按使用量付费的信用额度余额(v3 独立维度)

尚未发布。与上述链独立的轴——信用额度是一次性充值,而非订阅层级。
  • 新表 user_credits(user_id, balance_cents, currency) ——通过 Stripe Checkout mode='payment' 充值。
  • 消费顺序:订阅配额优先,然后是信用额度余额(仅在订阅耗尽后才开始扣除信用额度)。
  • 信用额度余额不可退款(预付款行业标准)。
  • UI 同时展示两个进度条:订阅配额:已使用 4.2M / 5M + 信用额度:剩余 $7.40

默认值

发货时的默认值——除特别说明外,所有值都可在安装后调整。
变量默认值可通过以下方式调整
billing_plans.monthly_token_quota (Free)1,000,000管理员 → 计费 → 套餐 → Free → 编辑
billing_plans.monthly_token_quota (Pro)5,000,000管理员 → 计费 → 套餐 → Pro → 编辑
system_settings.default_token_quota1,000,000(激活时与 Free 同步)管理员 → 系统设置 → 配额
system_settings.billing_enabledFALSE管理员 → 系统设置 → 计费
Pro 列表价格$20.00 USD / monthStripe Dashboard(价格对象)
Stripe webhook 事件订阅数6Stripe Dashboard → Webhooks
Stripe 价格缓存 TTL5 minutesstripe_client.py 中硬编码
订阅生命周期 cron每小时web/main.py 中的 APScheduler
免费层重置 cron每小时(日历月边界)web/main.py 中的 APScheduler

定价模型

V1 是一个统一订阅。免费 + 专业版,按月计费,仅支持美元。 V1 范围外(有意推迟至路线图):
  • 团队计划(Stripe 座位 / subscription.quantity
  • 年度计费
  • 多币种展示
  • 优惠券 / 促销代码
  • 税务处理(Stripe Tax 集成——需要单独的合规审查)
  • 基于使用量的计量 / 超额费用
  • 按次付费信用余额(一次性充值)
查看路线图了解后续计划。

故障排除

激活端点需要同时设置 STRIPE_SECRET_KEYSTRIPE_WEBHOOK_SECRET。确认它们存在于 .env 中,并且编辑后后端已重启。
要么是账单被禁用(切换开关为OFF),要么是请求签名验证失败(STRIPE_WEBHOOK_SECRET 不匹配)。检查Stripe仪表板→Webhooks→最近事件以查看实际错误正文。
checkout.session.completed webhook未到达你的后端。验证Stripe仪表板中的端点URL与 <your-domain>/api/webhooks/stripe 完全匹配,包括末尾路径。检查Webhook最近交付记录中的失败。
种子迁移写入了测试模式价格ID。激活生产账单后,通过管理员→账单→套餐→Pro→编辑,或通过直接SQL UPDATE,将Pro计划更新为使用你的实时 price_1***
在Stripe仪表板→设置→品牌中配置你的业务品牌。添加你的徽标、业务名称(例如”FIM Labs Pte. Ltd.”)和地址。Stripe会将这些应用于所有自动生成的收据和发票。
如果你的Stripe账户默认货币与收费货币不同,Stripe会在每次支付时进行转换(1.5-2%的差价)。在设置→银行账户和货币下添加匹配的结算货币,附加相同货币的银行账户,Stripe将路由相同货币的付款而无需转换。