# 账单 SDK

每个应用、每把开发者 Key、每个模型**花了多少钱**：平台在模型通道里给每次调用自动记账（token、音频秒数、按调用时的厂商价算好的成本），账单 SDK 把台账累计成**今日 / 本月 / 累计**，按应用、Key、模型、天拆开，给出**月底预测**、**预算**与**对账**。应用不用自己埋点；上线前还可以用**估算**先算清楚一个月要花多少。

```js
import { billing } from "/developer/sdk/v1/aidc.js";
```

## 怎么算的

| 计量 | 模型 | 成本 |
| --- | --- | --- |
| token | 对话、看图、Jev、`gpt-4o-mini-transcribe`（音频 token） | 未命中缓存的输入 × 输入价 + **命中缓存的输入 × 缓存价** + 输出（含推理）× 输出价；DeepSeek **按调用时刻分峰时 / 非峰时**（北京时间工作日 09–12、14–18 点为峰时，其余半价） |
| 分钟 | `gpt-transcribe` | 上游回报的秒数 × 分钟价 / 60 |
| 场次 | `gpt-live-transcribe`（实时转写） | 时长在上游（浏览器直连），平台只知道开了几场：**记为未计价**，账单另给「每场最多 5 分钟」的上限 |
| 次 | `marble-*`（[建模 SDK](modeling.md) 生成世界）、`marble-hq-mesh-export`（HQ 网格导出） | 按上游实收的 credits 结账（1,250 credits = US$1）；生成时按最坏情况预留，完成后按实收记一行 |

- 价目取模型厂商自己的价目页（`source: vendor`，逐个核对过、写明读取日期），其次是模型目录同步；运营方可以覆盖。`aidc billing prices` 看每个模型的单价与来源。
- **成本在调用那一刻按当时的价目算好写进台账**，价目后来变了也不改历史；账单只是把台账加起来。
- 不知道多少钱的调用（价目里没有、实时转写）是**未计价**：单独列出、写明原因，**不当成 0 元**加进总额。建模 SDK 结果还没定的世界（按最坏情况预留、上游还没结算）列在 `reserved`（笔数、最多多少钱），同样不进总额。
- 金额是美元标价（不是发票），六位小数的字符串，与台账同精度；各维度相加与总额**逐位相等**。显示成人民币用 `billing.usd(x, { fx: 7.1 })` 或 CLI `--fx 7.1`（只影响显示）。
- 时间一律 UTC：账期是 UTC 自然月，与应用额度的「UTC 自然日」同一口径。

## 看账单

```js
const s = await billing.summary();                    // 缺省当月；在应用里 = 当前应用，应用外 = 全公司
// s.today / s.month / s.total（累计，自 s.total.since）——每个都是 { requests, totalTokens, audioSeconds, sessions, costUsd, unpricedRequests … }
// s.apps（按应用，含占比、月底预测、预算）/ s.developerKeys / s.models（含单价）/ s.daily（按天 + 累计）
// s.forecast.monthEndUsd（最近 7 天日均 × 剩余天数）/ s.budget / s.unpriced（原因 + 上限）
billing.usd(s.month.costUsd);                         // "$0.4012"
const aug = await billing.summary({ month: "2026-08", app: null });   // 历史月份、全公司
```

```bash
aidc billing summary                        # 全公司、当月
aidc billing summary --app translate --month 2026-08 --fx 7.1
aidc billing records --app translate --all --csv > 9月明细.csv
```

账单、明细、对账只给**本公司开发者**（开发者 Key，或应用里的 developer 访客）；成员、公开链接的访客看不到。

## 规划：预算、预测、估算

**预算**写在应用清单里，到了就拒绝新的模型调用（`429 quota_exhausted`），下个月 1 日（UTC）恢复；账单里显示用了多少、按预测月底会不会超（用到 80% 或预测会超标「注意」）：

```json
{ "limits": { "dailyTokens": 1000000, "monthlyBudgetUsd": 20 } }
```

只想按某个数规划、不拦调用：`billing.summary({ budgetUsd: 50 })` / `aidc billing summary --budget 50`。预算只算已计价的成本，30 秒内生效（可能略超一点）。

**估算**：还没上线，先按现行价目算一个月要多少——每行一个模型 × 一种用法：

```js
const e = await billing.estimate({
  per: "day",                       // calls 按天（或 "month"）
  offPeakShare: 0.3,                // 30% 的调用落在 DeepSeek 非峰时（缺省 0 = 全按峰时，偏保守）
  budgetUsd: 20,
  items: [
    { model: "deepseek-flash", label: "翻译", calls: 200, inputTokens: 1500, cachedInputTokens: 1000, outputTokens: 300 },
    { model: "gpt-6-luna", label: "质检拍照", calls: 50, inputTokens: 20000, outputTokens: 500 },
    { model: "gpt-live-transcribe", label: "会议纪要", calls: 5, audioSeconds: 240 },
    { model: "marble-1.1", label: "工位建模", calls: 0.1, worldInput: "video" },   // 世界模型按最坏情况（与建模 SDK 预留同口径）
  ],
});
// e.items[i].perCallUsd / perDayUsd / perMonthUsd，e.total，e.budget.fits
```

```bash
aidc billing estimate -m deepseek-flash --calls 200 --input 1500 --cached 1000 --output 300 --budget 20
aidc billing estimate --file 估算.json      # 多行：{ "items": [ … ] }
```

## 对账

```js
const c = await billing.check({ month: "2026-09" });   // c.ok、c.checks、c.reprice
```

```bash
aidc billing check --month 2026-09          # 对不上时退出码 1
```

逐项复核账单的每个数：按应用 + 开发者 Key 相加、按模型相加、按天相加 = 本月；**另一条路**（逐行读台账、精确求和，不经分组 SQL）重算次数 / token / 金额；成本列直接相加 = 本月金额（证明列为未计价的行一分钱没丢）；累计 ≥ 本月。另外逐行按**现行**价目复算：台账没记命中缓存多少，所以一行的成本应当落在「全部命中」与「全部未命中」之间；按旧价目记的行会标成「高于 / 低于现行价」——这是提示，不算对账失败。

## API

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET | `/api/v1/developer/billing/prices` | 价目：计量方式、单价、来源（公开） |
| POST | `/api/v1/developer/billing/estimate` | 估算（开发者 Key 或应用票据） |
| GET | `/api/v1/developer/billing/{命名空间}/summary` | 账单：`?month=` `?app=` `?budget=` |
| GET | `/api/v1/developer/billing/{命名空间}/records` | 明细：`?month=` 或 `?from=&to=`，`?app=` `?model=` `?lane=` `?limit=` `?cursor=` |
| GET | `/api/v1/developer/billing/{命名空间}/check` | 对账：`?month=` `?app=` |

`?app=` 写应用 slug；同一家公司两个命名空间里有同名应用时写 `public/<slug>` 或 `cell-…/<slug>`。
