API 与 Metrics

English

HTTP API 基本是只读的,面向本地 dashboard、agent wrapper、Prometheus 和 operator smoke test。唯一会触发动作的 v1 endpoint 是受保护的手动 direct quota refresh。 0.x 版本可能新增 JSON 字段;客户端应该忽略不认识的字段。

OpenAPI 3.1 契约见 openapi.json。带版本的 /api/v1/* 路径是公共 集成面;旧的未版本化 /api/* JSON 路径已在 0.x API 清理中删除。

API 本身不是鉴权边界。--allowed-host 以及内置 Host / Origin 检查只是请求来源 guard,不是登录或授权机制。除非前面有带鉴权的 reverse proxy,否则 monitor 应继续 监听 127.0.0.1,不要直接暴露到 LAN 或公网。

浏览器里的 Privacy 开关只影响显示层。它会在页面渲染结果里打码邮箱和 token-like 字符串,但 API 和 metrics endpoint 会继续保留原始 payload,供 wrapper、agent、 Prometheus 和 smoke test 使用。

这些 endpoint 背后的数据流和 secret 脱敏模型见 安全自审计威胁模型

Endpoints

进程用 --demo 启动时,这些 endpoint 默认会在 127.0.0.1:4516 返回内置示例数据, 且 /api/v1/status 会包含 "demo": truesource = "demo"。Demo 模式不会读取 auth files、management key、SQLite history、benchmark summary 或 CPA endpoint。

脱敏示例

/api/v1/recommendations

{
  "contractVersion": "1.1",
  "sampledAt": "2026-04-20T12:00:00+00:00",
  "source": {"kind": "live", "text": "Live via CLIProxyAPI + direct Codex quota", "gatewayOk": true},
  "routingPolicy": {
    "scoreMax": 100,
    "capacityWeightUnit": "plus",
    "hardBlocks": [
      "routeEligible=false",
      "tone=bad",
      "status disabled/unavailable/invalid/auth invalid/cooldown",
      "exhausted quota windows"
    ]
  },
  "summary": "3 routable accounts · 1 blocked account · top score 86",
  "routableCount": 3,
  "blockedCount": 1,
  "topScore": 86,
  "items": [
    {
      "selector": {
        "authName": "auth-redacted.json",
        "authIndex": "acct-redacted",
        "accountKey": "acct-redacted"
      },
      "authIndex": "acct-redacted",
      "accountKey": "acct-redacted",
      "planKind": "plus",
      "title": "account-redacted@example.invalid",
      "badge": "Plus",
      "summary": "Active · 5h 80% · weekly 80%",
      "routingScore": 86,
      "routingEligible": true,
      "routingBlockedReasons": [],
      "scoreComponents": {"capacity": 36, "health": 25, "plan": 5, "load": 10, "reclaim": 10},
      "capacityWeight": 1.0,
      "quotaWindows": [
        {"id": "5h", "state": "known", "percent": 80, "resetsInSeconds": 3600},
        {"id": "week", "state": "known", "percent": 80, "resetsInSeconds": 86400}
      ],
      "reclaimEligible": true
    }
  ]
}

/api/v1/health

{
  "title": "Health",
  "state": "warn",
  "summary": "1 item needs review.",
  "pill": "1 action",
  "actions": [
    {
      "kind": "threshold",
      "tone": "bad",
      "title": "5h capacity below threshold",
      "badge": "Threshold",
      "summary": "0.40 Plus < 0.50 Plus"
    }
  ],
  "sources": [],
  "recentChanges": [],
  "actionCount": 1
}

稳定字段

/api/v1/recommendations/api/v1/health 是推荐给 wrapper 依赖的契约。 自动化选号应使用 /api/v1/recommendations,并把深层 /api/v1/status.tabs.* payload 当成 UI 实现细节,除非这些字段已经在本文档或 openapi.json 中明确列为稳定字段。

Stats Series

/api/v1/stats/series 是 Stats workbench 背后的稳定机器可读接口。它读取 monitor SQLite 里去重后的 timestamped usage details;因此进程未启用 --state-db, 或 CPA 还没有返回带时间戳的 usage detail 行时,这个接口会返回空视图。

支持的 query 参数:

CSV 导出列如下:

timestamp,series_id,series_label,requests,tokens,failed,request_text,token_text,failure_rate

浏览器会把 Stats 控件状态,例如 range、metric、group、smooth 和 display mode, 存在 localStorage。这些偏好只是显示状态,不会修改 API payload 或 monitor SQLite history。

Client labels 从 JSON 文件读取:

{
  "clients": [
    {"apiName": "sk-example-from-cpa", "label": "Alice"},
    {"api_name": "rotated-api-name", "label": "Alice"}
  ]
}

--client-labels-file /path/to/client-labels.json 传入,或设置 CODEX_QUOTA_MONITOR_CLIENT_LABELS_FILE。这个文件应按运行时 secret 处理; 不要把真实 API name 写进公开文档或 Nix store 文本。

Prometheus

examples/prometheus/prometheus.yml 提供 scrape 示例, examples/prometheus/alerts.yml 提供 starter alerts。常用指标包括:

CLI 辅助入口

CLI 参数覆盖环境变量,环境变量覆盖 TOML 配置文件。用 --config /path/to/config.tomlCODEX_QUOTA_MONITOR_CONFIG 指定配置;用 --config off 忽略配置文件。 浏览器需要通过非 loopback 域名或 IP 访问 dashboard 时,使用 --allowed-host / CODEX_QUOTA_MONITOR_ALLOWED_HOSTS;多个 authority 用逗号分隔,例如 monitor.lan,192.0.2.10。不写端口表示允许这个 host 的任意浏览器侧端口; 写成 :4515 则要求 Host / Origin 使用指定端口。这个 allowlist 不会鉴权访问者。 反代时这里要填浏览器访问用的 hostname,例如 quota.example,不是 loopback upstream。v1 浏览器 UI 期望部署在该 hostname 的根路径;暂不支持 path-prefix 部署。