Lemon Squeezy 用量计费适合 AI credits、插件调用次数、API 请求量、seat 之外的可变消耗。它的坑也很集中:后台看起来是订阅,代码里也成功创建了客户,但当前用量接口 404,或者客户页显示 12 次、Lemon Squeezy 只准备收 5 次。
排查时不要先改代码。先拿到 4 个证据:variant 是否启用 metered billing、subscription item id、最近一次 usage record 请求体、webhook 事件入库记录。
快速判断问题类型
| 现象 | 最大概率原因 | 查哪里 | 关键证据 |
|---|---|---|---|
| current usage 返回 404 | product/variant 未启用 usage-based billing | Product / Variant 设置 | 「Usage is metered?」是否开启 |
| usage record 201/200 但数值不对 | action 和 aggregation 错配 | usage record 请求体 | increment / set |
| checkout 金额是 0 | 这是 metered billing 默认行为 | Checkout 测试订单 | 是否有 setup fee |
| 上报成功但应用里没同步 | webhook 入库或重放失败 | webhook 日志 | event id、签名、处理状态 |
| 客户权益对不上 | 存了 subscription id,没存 subscription item id | 订单同步表 | subscription_item_id |
Lemon Squeezy 帮助文档把 usage-based billing 也称为 metered billing。它启用在 product 或 variant 设置里,后续账单按你通过 API 上报的用量在下一次 renewal 处理。
current usage 返回 404 的原因
当前用量接口是:
GET /v1/subscription-items/:id/current-usage
Lemon Squeezy API 文档明确写了一个容易误判的行为:这个 endpoint 只用于启用 usage-based billing 的订阅;如果关联的 subscription product/variant 没有开启 usage-based billing,会返回 404 Not Found。
注意,HTTP 404 本身只表示服务端找不到目标资源;在这个接口里,要按 Lemon Squeezy 的业务文档解释,不能把它直接等同于「客户没有用量」。
所以 404 的排查顺序是:
- 这个
:id是不是 subscription item id,而不是 subscription id、variant id、customer id。 - 这个 subscription item 关联的 variant 是否开启
Usage is metered?。 - 测试环境和生产环境的 variant 是否是同一个配置。
- 客户是不是从旧 checkout 买入,旧 variant 当时还没开 metered billing。
- 你是否在迁移产品后仍用老的 subscription item 查询。
如果只是当前周期没有用量,合理预期应该是能拿到当前周期 meta,并看到 quantity 为 0 或已聚合后的数值;文档里的 404 指向的是配置限制,不是「没用过」。
配置层要查的 5 个字段
打开 Lemon Squeezy 后台的 product/variant,不要从代码里猜。
| 配置项 | 正确检查方式 | 出错后果 |
|---|---|---|
| Usage is metered? | 在 product/variant 设置里确认已开启 | current usage 404,usage 上报无法按预期计费 |
| Pricing model | flat-rate、standard、package、volume、graduated 的组合 | 价格阶梯和用量单位解释错 |
| Usage aggregation | Sum、Most recent、Maximum 等 | action 选错后累计或覆盖异常 |
| Setup fee | 是否需要 checkout 时立即收费 | 客户看到 0 美元误以为免费 |
| Variant id | 测试、生产、旧版本是否混用 | 旧客户和新客户计费口径不一致 |
官方帮助页说明,usage-based billing 启用后,客户在 checkout 不会被立即收取用量费用,默认按钮会从 Pay 变成 Create subscription。除非你配置 setup fee,否则初始 charge 是 0;checkout 上传的 quantity 也会被忽略。
这对 AI 工具很重要。比如你卖「每 1,000 次调用按量计费」,用户开通当天不该因为 quantity=1000 被立即扣费;真正账单来自上一个 billing period 内的 usage records。
usage records 漏报排查
创建用量记录的 endpoint 是:
POST /v1/usage-records
核心字段只有几个,但每个都容易错:
| 字段 | 文档含义 | 排查口径 |
|---|---|---|
quantity | 正整数,用来表示上报的用量 | 不能传负数;退款和冲正另做内部账 |
action | increment 或 set | 省略时默认 increment |
subscription-item relationship | 这条用量属于哪个 subscription item | 不要传 subscription id |
subscription_item_id | 返回对象里的订阅项编号 | 存入内部 usage ledger |
action 是漏报和重复计费的分水岭。
如果 aggregation 是 Sum of usage during period,increment 才合理。你每次上报 quantity=1,Lemon Squeezy 会把当前周期内的记录加总。
如果 aggregation 是 Most recent usage during a period 或 Most recent usage,应该用 set。这表示「当前总用量是 500」,不是「再增加 500」。把 increment 用在这类场景,会把 dashboard 里的总量越推越高。
一个最小请求体应该长这样:
{
"data": {
"type": "usage-records",
"attributes": {
"quantity": 1,
"action": "increment"
},
"relationships": {
"subscription-item": {
"data": {
"type": "subscription-items",
"id": "1"
}
}
}
}
}
生产环境建议给每次上报留 5 列日志:内部用户 id、subscription_item_id、quantity、action、Lemon Squeezy usage record id。只存「接口成功」四个字,月底无法解释为什么少收 27 次调用。
当前用量与自有用量表的对账
开发者指南说明,current usage 的 quantity 会在你发送 usage record 后更新,并反映下一张 invoice 会使用的 billable usage;它会按照你配置的 aggregation 计算。
这句话有两个含义。
第一,current usage 不是原始流水表。它是 Lemon Squeezy 算完聚合后的结果。你自己的 usage ledger 仍然要保存每次 API 调用、消息生成、插件运行或 credit 扣减。
第二,current usage 是和 subscription item 绑定的。一个客户如果从 Basic 升到 Pro,或者从旧 variant 迁移到新 variant,你要把旧 subscription item 和新 subscription item 分开对账。
推荐对账方式:
| 你的系统 | Lemon Squeezy | 对账频率 |
|---|---|---|
| 原始调用日志 | 不直接对应 | 实时写入 |
| 内部 usage ledger | usage records | 每次上报后记录返回 id |
| 客户用量页 | current usage meta.quantity | 每次刷新或定时同步 |
| 月度收入表 | subscription invoice | renewal 后对账 |
如果客户投诉「页面显示 100,账单只收 80」,看 aggregation。Maximum usage during period、Most recent usage、Sum during period 得出的 billable usage 本来就不同。
webhook 重放与环境问题处理
用量上报本身靠 usage records API,webhook 负责把 Lemon Squeezy 的订阅、客户、发票状态同步回你的系统。2026-02-25 API changelog 新增了 customer_updated webhook event,用来监听 customer profile updates 并同步到应用。
这类更新不改变 usage record 的字段,但会暴露同一个工程问题:你的 webhook 不能只「收到就改库」,还要能查重、重放、分环境。
建议每个 webhook event 入库时保存:event id、event type、test/live 环境、关联 customer id、subscription id、subscription item id、原始 payload、处理状态、错误信息。
如果你在本地、预发、生产之间频繁切换回调地址,后台登录、API key、webhook secret、Cloudflare 或 GitHub 部署环境也会变多。团队多人处理付款和订阅事故时,把核心后台放在固定设备和固定网络规范下,用海外银行 + Stripe + AI 工具全场景承载这些高风险操作,至少能减少「谁在什么环境改了 webhook」这类追查成本。
排查 webhook 时按这个顺序:
- Lemon Squeezy 后台是否真的发出了对应 event。
- 你的 endpoint 是否返回 2xx。
- 签名校验失败有没有被记录,而不是直接丢弃。
- event id 是否被幂等逻辑误判为已处理。
- test mode 和 live mode 是否写进了同一张客户表。
- 重放后是否只更新状态,不重复发放权益。
重新建 variant 还是继续打补丁
这几种情况建议新建 variant,并把旧客户留在旧口径里,别硬改:
- 旧 variant 原来不是 usage-based,已经有客户购买。
- 你从 quantity-based billing 改成 usage-based billing。
- aggregation 从 Sum 改成 Most recent,历史账单解释会变。
- 单位从「次」改成「千 token」或「credit」。
- setup fee 逻辑发生变化。
重新建 variant 的好处是账单历史清楚。坏处是迁移要写 customer communication、权益映射和内部报表备注。对已经收过钱的订阅产品,清楚比省事重要。