API 与 Metrics
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
GET /healthz:只表示进程存活;不检查 CPA、management key、auth-dir、SQLite 或 benchmark import。GET /api/v1/status:浏览器 UI 使用的完整 dashboard snapshot。顶层 envelope 稳定;深层tabspayload 面向 UI,在0.x阶段按 additive 方式演进。GET /api/v1/stats:更窄的 Stats 标签页 payload,包含 CPA live details、CPA cumulative counters、SQLite history summary、数据源和备份提示。GET /api/v1/stats/series:基于 SQLite history 的 Stats 时间序列 workbench payload,支持 token/request 曲线、分组、平滑偏好,以及把当前视图导出为 JSON 或 CSV。GET /api/v1/recommendations:给 wrapper / agent 使用的按 routing score 排序的账号列表。 这是自动化选号的契约面;wrapper 应使用它,而不是抓取深层/api/v1/status.tabs.*UI payload。GET /api/v1/health:聚合账号动作、monitor 数据源状态和 recent changes 的运维健康 payload。POST /api/v1/quota/refresh:受保护的手动 direct quota refresh。默认浏览器 UI 会发送页面内X-Codex-Quota-Monitor-Refresh-Token;旧的manual_quota_refresh_auth = "management-key"部署改用Authorization: Bearer <management-key>,"none"则只适合可信本地部署。它会排队全量刷新 primary、recovery 和 discovery 账号的 direct quota,并跳过不属于 direct-quota policy 的账号;没有旧版/api/*alias。发送{"scope":"disabled-diagnostics"}会对 operator-disabled Codex 账号做一次诊断探测,但这些账号仍保持 disabled、不可路由, 且不计入容量。最新 disabled probe 结果会跨普通自动 quota refresh 保留,直到下一次 disabled-diagnostics 探测或进程重启。GET /metrics:Prometheus text metrics。
进程用 --demo 启动时,这些 endpoint 默认会在 127.0.0.1:4516 返回内置示例数据,
且 /api/v1/status 会包含 "demo": true 和 source = "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/status:available、source、sourceText、displayTimezone、displayTimezoneLabel、summary、tabs、recommendations。summary.activityLine是适合 UI 展示的请求/token 活动摘要。 Fast/Routing gateway policy 状态不再属于公开 status payload。/api/v1/recommendations:contractVersion、sampledAt、source、routingPolicy、routableCount、blockedCount、topScore、items。source.kind是 snapshot source,source.text是给人看的 source summary,source.gatewayOk对应 gateway liveness。- 推荐项:
selector、authIndex、accountKey、planKind、title、badge、summary、detail、routingScore、routingEligible、routingBlockedReasons、scoreComponents、reasons、capacityWeight、quotaWindows、reclaimEligible、reclaimWindow。routingBlockedReasons对 routable 账号为空;被阻断账号会给出auth_invalid、operator_disabled、cpa_retry_after、status_invalid、cooldown或 quota window exhausted 等稳定 reason slug。quotaWindows只包含脱敏后的 direct-quota window 状态:window id、state、percent、 reset 时间、remaining text 和 stale 状态。capacityWeight使用 Plus 单位:Plus 和 Team 为1.0,Prolite 为5.0,Pro 为20.0,不参与聚合的 plan、operator 手动停用账号或上游 deactivated 账号为0.0。 recommendations payload 不返回 access token、management key、auth-file path、 download URL 或原始 auth JSON。 - Reset 行:
account、remainingText、timeText、timezoneLabel、resetAt、resetsInSeconds、displayResetSource。 /api/v1/stats:title、summary、live、cumulative、history、backup、sources、footnote。live只来自 timestamped CPA details;cumulative是最新 CPA 累计 snapshot;history是启用--state-db后的 monitor SQLite 数据。交互式时间线在/api/v1/stats/series;Stats tab payload 只保留 summary 和数据源状态。/api/v1/stats/series:title、summary、defaults、options、query、available、bucketSeconds、range、totals、series、breakdown、export。/api/v1/health:title、state、summary、pill、actions、sources、recentChanges、actionCount。 operator 手动停用账号会从路由和容量中排除,但除非 CPA 同时报告 unavailable 或 invalid auth 状态,否则不会计入 Health action。禁用账号探测结果会出现在 status account payload 的disabledProbe字段中,仅用于诊断展示。普通 quota refresh 会保留最后一次 disabled probe 结果,不会把它重置为 unknown。
/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 参数:
range:1h、6h、24h、7d、30d或all;默认24h。metric:tokens或requests;默认tokens。group:total、account、client、model或api;默认total。 配置--client-labels-file后,client是推荐的共享 client / friend 分账视图。未映射 client 会显示确定性的短 fingerprint,不直接展示原始apiName/api_name。兼容用的api分组会保留 CPA 原始 API name, 可能暴露敏感值。top:按用量排序的展示项目数量,范围1到20;默认8。 分组视图会用它限制图表曲线和分解行;total图表仍只有一条总曲线, 但右侧分解仍受它限制。smooth:默认true;0、false、off、no会关闭平滑。mode:bucket表示时间桶总量,rate表示每分钟速率;默认bucket。format:省略时返回 JSON;csv返回text/csv; charset=utf-8。
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。常用指标包括:
codex_quota_monitor_snapshot_availablecodex_quota_monitor_snapshot_source{source=...}codex_quota_monitor_gateway_upcodex_quota_monitor_health_action_countcodex_quota_monitor_routable_accountscodex_quota_monitor_top_routing_scorecodex_quota_monitor_capacity_known_plus_units{window=...}codex_quota_monitor_capacity_tracked_plus_units{window=...}
CLI 辅助入口
codex-quota-monitor是 canonical 可执行文件;cqm是等价短别名。codex-quota-monitor print-config:打印解析后的非敏感配置。codex-quota-monitor --demo:默认在4516端口提供内置示例数据,用于零 secret 预览 dashboard。codex-quota-monitor doctor:检查 CPA 可达性、management key、配置文件加载、auth-dir 权限、SQLite 状态路径、端口可绑定性和风险监听地址。codex-quota-monitor doctor --json:输出机器可读检查结果。codex-quota-monitor init:打印或写出 starter config、systemd 和 Docker artifact。codex-quota-monitor redact:共享前为 JSON、JSONL、CSV、Markdown/text 和 SQLite support artifact 生成脱敏副本。codex-quota-monitor export-history --state-db /path/to/history.sqlite3 --output backup.json:导出 monitor SQLite history 的原生 JSON 备份。codex-quota-monitor import-history --state-db /path/to/history.sqlite3 backup.json:幂等导入原生 JSON 备份。
CLI 参数覆盖环境变量,环境变量覆盖 TOML 配置文件。用 --config /path/to/config.toml 或 CODEX_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 部署。