Files
new-api-key-usage/docs/references/NewAPI-接口范围.md
T
skycurtain c32548e598 fix(web): 支付表列与表单语义校准
充值金额/实付金额文案与 dataIndex;期间两行;备注列收窄;
选用弹层 booting 不闪登录;订阅 paid_at 不默认当前时间。
2026-10-09 22:41:04 +08:00

23 KiB
Raw Blame History

NewAPI 接口范围

计费平台在 NewAPI 中可用的接口参考:每个接口的鉴权档位、请求与返回结构、字段语义、实测行为与对平台的用途——平台所有上游调用都出自这份文档。

依据:NewAPI 源码考证 + 接口实测 · 实测环境:NewAPI 实例 · 上游仓库:https://github.com/QuantumNous/new-api


0. 通用说明

认证方式

所有需要凭证的接口均使用 API key 鉴权,在请求头中携带:

Authorization: Bearer sk-xxxxxxxxxxxx

不需要账号登录态(access token / session)——这是仅凭 sk-key 即可查询的关键前提。BaseURL 即 NewAPI 站点地址,路径直接拼接、无多余前缀。

关键开关:DisplayTokenStatEnabled

  • billing 接口(⑤⑥)受影响:开启 → 返回 token 级额度;关闭 → 回退账号级额度(会暴露整个账号余额)
  • /api/usage/token、/api/log/token 不受影响,恒返回 token 级数据
  • 实测已确认当前站点开关为开启状态;开关位于后台设置 → 计费设置(Billing)→ 货币与显示(Currency & Display)→ Display Token Statistics,仅管理员可改

换算参数:QuotaPerUnit

  • 默认 500000(源码 common/constants.go,锚点 $0.002 / 1K tokens),管理员可改且改后立即全站生效(详见 ④)
  • 实现时必须从 GET /api/status 实时读取,不得硬编码
  • 实测交叉验证:/api/usage/token 的 total_used = 673,419,457 ÷ 500000 = 1346.84 美元;/v1/dashboard/billing/usage 的 total_usage = 134,683.8914 美分 ÷ 100 = 1346.84 美元——完全吻合

1. 鉴权三态总览

本项目对接的接口按鉴权中间件分三档:

鉴权档 中间件 语义 本项目的请求方式
公开(none) 无 / HeaderNavModulePublicOrUserAuth 不持有任何凭证即可访问 直接请求,无需 key
严格(strict) TokenAuth 校验 key 有效、未过期、有剩余额度;无效直接被拒 携带 sk-key 请求
宽松(lenient) TokenAuthReadOnly 只验 key 存在且用户未封禁;过期/额度耗尽仍可查,但显式禁用(Disabled)会被 401 拒绝(middleware/auth.go 注释原文:only explicitly disabled tokens are denied) 携带 sk-key 请求;本项目主要依赖此档

失败状态码全集(2026-09-13 源码复核):401 = key 不存在(MsgTokenInvalid)或 token 被显式禁用(MsgTokenStatusUnavailable);403 = 账号被封禁;500 = 数据库错误。→ 摘除计数只认 401;403 / 500 视为其他故障,不计入。宽松档允许 key 过期(Expired)与额度耗尽(Exhausted)状态查询。

2. 接口清单

公开接口组(无需 sk-key)

① GET /api/user/groups — 用户分组与倍率

  • 返回:站点配置的用户分组(default / vip 等)与倍率;未启用分组时 data 为空对象(当前站点实测即此状态)
  • 用途:解释「同一模型为什么计费不同」——分组倍率影响同一模型的实际消耗
  • 本项目用途:低优先级;仅当站点启用分组倍率后才有内容

② GET /api/perf-metrics/summary — 全站模型服务质量

  • 参数:hours(统计窗口小时数,默认 24)
  • 返回:每个模型的 avg_latency_ms(平均延迟)、success_rate(成功率 %)、avg_tps(每秒 token 数)、recent_success_series(按小时采样的成功率时间序列);明细版 /api/perf-metrics?model=xxx(model 必填,另支持 group/hours)
  • 鉴权细节:HeaderNavModulePublicOrUserAuth("pricing")——默认公开,管理员可为 pricing 模块开启 requireAuth
  • 实测:HTTP 200,含站点真实模型的服务质量数据
  • 本项目用途:高——本工具独有视角。单个 sk-key 日志看不到全局服务质量;使用者反馈「慢/报错多」时,此接口能定位是模型问题还是自身问题。技术设计时可作为「模型健康度」功能的数据源

③ GET /api/rankings — 全站模型用量排行

  • 参数:period(统计周期,默认 week)
  • 返回:每个模型的 rank(名次)、previous_rank(上期名次)、total_tokens(总用量)、share(份额)、growth_pct(环比增长 %)
  • 实测:HTTP 200,14KB 数据
  • 本项目用途:中——项目作者选「主推模型」(便宜且稳定)的数据依据;配合②的成功率可识别衰退模型

④ GET /api/status — 站点配置与计费参数

  • 返回:60+ 字段,与本项目相关的计费字段:quota_per_unit(换算比率当前生效值,管理员可改)、quota_display_type(USD/CNY/TOKENS,影响 billing 接口语义)、usd_exchange_rate、price 等
  • 本项目用途:关键——换算比率的唯一权威来源,实现时必须实时读取、不得硬编码;同时感知 quota_display_type 切换(若切到 CNY/TOKENS,billing 接口数字语义会变)。实测当前站点:quota_per_unit = 500000、quota_display_type = USD、usd_exchange_rate = 6.8
  • quota_per_unit 的行为事实(2026-09-13 源码评估):由全局变量承载,改设置是「先写库、再热更新内存」(model/option.go 的 UpdateOption → updateOptionMap)——改后立即全站生效、无需重启。三条关键行为:
    • 无历史:options 表一 key 一行、改即覆盖——任何接口都读不到过去的取值;管理审计只记"键名被改过"、不记值
    • 无编辑入口:后台设置页该字段默认隐藏;当显示类型为 TOKENS 或取值非默认(≠500000)时才显示,且显示时仍为只读(disabled)——源码 web/src/features/system-settings/general/pricing-section.tsx(2026-09-29 main 分支复核);修改只能走 API(PUT /api/option/,Root 权限,热更新内存立即生效)
    • 解读跟随当前值:一切对外的金额换算(历史记录解读、billing 接口、界面显示)都在读取时实时使用当前值——改它 = 全站金额表达整体平移(数据库里的 quota 整数不受影响)

严格鉴权组(TokenAuth,sk-key)

⑤ GET /v1/dashboard/billing/subscription — 总额度上限(美元)

  • 返回结构(源码 controller/billing.go:13 → GetSubscription):
{
    "object": "billing_subscription",
    "has_payment_method": true,
    "soft_limit_usd": 100000000,
    "hard_limit_usd": 100000000,
    "system_hard_limit_usd": 100000000,
    "access_until": 0
}
  • 字段:hard_limit_usd(总额度上限,美元;三个 limit 字段同值)、access_until(token 过期时间,Unix 秒,0 = 永不过期)
  • 注意:无限额度 key 返回 100000000(一亿占位值,无参考意义);受 DisplayTokenStatEnabled 与 quota_display_type 影响(USD 模式直接是美元,CNY 模式做货币转换,Tokens 模式是原始 token 数)
  • 路径变体:/dashboard/billing/subscription(不带 /v1 前缀)是同一接口,为兼容不同客户端写法——测一组即可
  • 本项目用途:中——按 key 统计的「累计剩余」列候选数据源;与⑥相减可得剩余额度

⑥ GET /v1/dashboard/billing/usage — 累计已用(美分)

  • 返回结构(源码 controller/billing.go:75 → GetUsage):
{
    "object": "list",
    "total_usage": 134683.8914
}
  • 字段:total_usage(累计已用,单位美分,÷100 = 美元;从 key 创建至今累计,非当月)
  • 注意:受 DisplayTokenStatEnabled 与 quota_display_type 影响(USD 模式才是美元);hard_limit_usd(⑤)− total_usage ÷ 100(⑥)= 剩余额度(仅有限额 key 有意义);可与⑧的 total_used ÷ quota_per_unit 交叉对账(不一致 = 站点改过比率,见④)
  • 路径变体:/dashboard/billing/usage 同⑥
  • 本项目用途:中——对账与校验用途

⑦ GET /v1/models — 可用模型列表

  • 返回:当前 key 可用的模型列表,OpenAI 兼容格式(data[].id 为模型名)
  • 变体(与用量统计无关,列出仅为完整覆盖):/v1/models/:model 单模型详情、/v1beta/models(Gemini 格式)、/v1beta/openai/models(OpenAI 格式,Gemini 路由下)
  • 已知限制:/v1/models 查数据库 abilities 表(渠道实际配置),而 /v1/models/:model 查代码内硬编码的静态模型列表(openAIModelsMap)——渠道配了新模型或自定义模型名但代码未收录时,会出现"列表里有但单查返回 model_not_found"的现象;不影响实际模型调用
  • 本项目用途:低——调试期验证渠道配置用

宽松鉴权组(TokenAuthReadOnly,sk-key)

⑧ GET /api/usage/token — token 级用量汇总(原始 quota)

  • 返回结构(源码 controller/token.go → GetTokenUsage):
{
    "code": true,
    "message": "ok",
    "data": {
        "object": "token_usage",
        "name": "令牌名称",
        "total_granted": 6012,
        "total_used": 673419457,
        "total_available": -673413445,
        "unlimited_quota": true,
        "model_limits": {},
        "model_limits_enabled": false,
        "expires_at": 0
    }
}
  • 字段:
字段 类型 说明
name string 令牌名称
total_granted int 总额度 = RemainQuota + UsedQuota(原始 quota 单位)
total_used int 累计已用(原始 quota 单位)。从 key 创建以来累计,非当月;换算美元 ÷ quota_per_unit
total_available int 剩余 = granted − used。无限额度时为负数,无实际意义
unlimited_quota bool 是否无限额度。true 时 granted/available 无实际意义
model_limits / model_limits_enabled object / bool 模型限制
expires_at int 过期时间(Unix 秒),0 = 永不过期
  • 注意:额度单位是原始 quota 整数,需自行换算美元;禁用再解禁不会重置 total_used(源码验证:Update() 的 .Select(...) 列表不含 used_quota);key 耗尽后仍可查(用完也能对账)
  • 本项目用途:高——按 key 统计「全周期累计(已用/剩余)」的直接数据源

⑨ GET /api/log/token — 最近 1000 条调用日志

  • 返回结构(源码 controller/log.go:62 → GetLogByKey):
{
    "success": true,
    "message": "",
    "data": [
        {
            "id": 123456, "user_id": 12, "created_at": 1751328000, "type": 2,
            "content": "模型倍率 1.0,分组倍率 1.0", "username": "用户名", "token_name": "令牌名",
            "model_name": "gpt-4o", "quota": 2500, "prompt_tokens": 1500, "completion_tokens": 500,
            "use_time": 2, "is_stream": true, "channel": 0, "channel_name": "", "token_id": 100,
            "group": "default", "ip": "",
            "request_id": "20260911113652…",
            "other": "{\"billing_source\":\"subscription\",\"cache_tokens\":29056,\"frt\":3931,\"model_ratio\":0.075,\"request_path\":\"/v1/messages\",\"stream_status\":{\"status\":\"ok\"},…}"
        }
    ]
}
  • 字段说明(共 21 个字段;按实测响应 + 上游源码校正,2026-09-11):
字段 类型 说明
id int 展示序号,每次从 1 重编——跨请求无意义,绝不能用于去重
user_id int 账号 ID(同一实例内恒定)
created_at int 调用时间(UTC Unix 秒,三字段交叉实测)
type int 日志类型(取值见下);token 日志实见 2=消费、5=错误
content string 消费记录为空串;错误记录为错误详情文本
username / token_name string 账号用户名 / 令牌名
model_name string 调用的模型名
quota int 本次消耗的 quota(换算美元 ÷ quota_per_unit);错误记录为 0
prompt_tokens / completion_tokens int 输入 / 输出 token 数;错误记录为 0
use_time int 耗时(秒);错误记录为 0
is_stream bool 是否流式
channel / channel_name int / string 渠道 ID / 渠道名(普通用户视角后者为空串)
token_id int 上游 token ID(对账用)
group string 分组名(默认 default)
ip string 请求 IP(普通用户视角为空串)
request_id string 请求 ID(yyyyMMddHHmmss 前缀 + 随机串);源码写入有兜底保证非空——去重唯一依据。补充实测(2026-09-15):错误场景下不保证行级唯一——1000 条实测样本中 8 个 request_id 各对应 3 条 type=5 错误记录(同一请求的多次失败 / 重试,content 的 status_code 可不同);按 request_id 去重会把它们合并为 1 条(消费类 type=2 样本中未观察到重复)
upstream_request_id string 上游请求 ID;JSON tag 为 omitempty——空值时不出现、有值时才出现,消费方需按「可选字段」处理
other string JSON 字符串,扩展信息(结构见下)
  • type 完整取值(上游源码 model/log.go;常量注释明确「刻意不用 iota,以保证枚举值永不改变」):
值 常量 含义 可能出现在 token 日志?
0 LogTypeUnknown 未知 兜底值
1 LogTypeTopup 充值 否(账号级,无 token_id)
2 LogTypeConsume 消费 是(实测)
3 LogTypeManage 管理操作 否(审计类)
4 LogTypeSystem 系统 否
5 LogTypeError 错误 是(实测)
6 LogTypeRefund 退款 可能(任务计费链路带 token_id)
7 LogTypeLogin 登录 否(账号级)

本接口按 token_id 过滤、不按 type 过滤——凡是「带 token_id 写入」的类型都可能返回。

  • other 字段(JSON 字符串,内容随 type 变化,实测 2026-09-11):

    • 消费记录(type=2):billing_source、cache_ratio、cache_tokens、completion_ratio、frt、group_ratio、model_price、model_ratio、reasoning_effort、request_conversion、request_path、stream_status(对象)、subscription_*(订阅维度,共 8 个)、user_group_ratio、wallet_quota_deducted
    • 错误记录(type=5):error_code、error_type、request_path、status_code
    • 注:普通用户视角下,服务端会先对 other 做「可见性过滤」再返回——上表为过滤后实际可见的键
  • 关键限制:

    • 硬上限 1000 条:固定返回最近 1000 条(Limit(common.MaxRecentItems),MaxRecentItems = 1000,common/constants.go);不支持任何请求参数(源码不读任何 c.Query(),无分页 / limit / 时间过滤);固定按 id desc 排序(最新 1000 条)
    • 超过 1000 条的旧记录无法获取:无法翻页、无法扩大 limit;实测当前站点日志速率下 1000 条 ≈ 3 天窗口
    • 大响应:pretty-print 后 2~4MB——同步引擎需直面的单次响应体积
  • 本项目用途:核心——增量同步引擎的唯一数据源;本地攒全量后,任意时间范围的用量/明细/模型统计都是本地聚合查询

3. 换算与 quota 计算

核心换算公式

原始 quota ÷ quota_per_unit(默认 500000) = 美元

消费记录的 quota 是怎么算出来的(实测反推,2026-09-13)

按 tokens 计费的模型,quota 在请求时由「倍率 × 用量」算出并固化进日志(此后不再变化):

quota = ( (prompt_tokens − cache_tokens)             ← 提示 tokens(未命中缓存部分)
          + cache_tokens × cache_ratio                ← 缓存命中部分按折扣
          + completion_tokens × completion_ratio )   ← 补全 tokens 按倍率
        × model_ratio                                 ← 模型倍率
        × group_ratio                                 ← 分组倍率
  • 验证:6/6 条实测日志逐条吻合(差值仅为四舍五入)
  • 按次计费模型走 model_price 分支:quota = model_price × QuotaPerUnit × group_ratio(源码 relay/helper/price.go)
  • 公式中没有 QuotaPerUnit:倍率与美元的锚定(model_ratio = 1 ⇔ $0.002 / 1K tokens)已隐含它——倍率制下改 QuotaPerUnit 等于全站重定标;美元定价路径(model_price / 表达式 $/1M)才显式乘 QuotaPerUnit

4. 范围之外(sk-key 不可达)

4.1 不存在的接口(404)

路径 状态
/v1/usage、/v1/quota、/api/token/self 不存在

4.2 存在但需要登录态的接口(sk-key 访问 401)

支持时间范围查询与过滤,但必须用账号登录态(access token + New-Api-User header):

路径 鉴权 能力
/api/log/self UserAuth() 支持 start_timestamp、end_timestamp、token_name 过滤,返回日志明细
/api/log/self/stat UserAuth() 支持时间范围 + token_name,返回 quota 汇总(调 SumUsedQuota)——NewAPI 中最适合算"当月用量"的接口,是「按时间段统计用量」无法纯 sk-key 实现的核心障碍
/api/data/self UserAuth() 按日聚合的看板数据
/api/token/ (GET/POST/PUT/DELETE) UserAuth() token 的增删改查
/api/user/self UserAuth() 用户自身信息

4.3 订阅信息

  • 存在完整列表接口,但鉴权是 UserAuth()(账号登录态),不是 sk-key(源码 router/api-router.go · controller/subscription.go:GetSubscriptionSelf,2026-10-08 核对):

    路径 鉴权 能力
    GET /api/subscription/self UserAuth() 返回 all_subscriptions(含已过期):id、start_time/end_time(Unix 秒)、status、amount_total/amount_used、created_at 等;另有 subscriptions、billing_preference
    GET /api/subscription/plans UserAuth() 套餐列表
    /api/subscription/admin/* AdminAuth() 管理端绑定/作废等,与本项目无关
  • sk-key(TokenAuth / TokenAuthReadOnly)挂不上这些路由——钱包页在 F12 里看到的 JSON 即 GET /api/subscription/self,需网页登录 Cookie/会话,不是 Authorization: Bearer sk-…

  • 「没有免 auth 的接口」结论仍成立;并非漏查,而是查询面从未对 sk-key 开放。UI 只显示过期时间,是前端展示裁剪,底层数据在上述接口里

  • 订阅 id 与日志 other.subscription_id 同体系(作者 JSON 中 id: 44/22/6 可与日志对账)

  • 对应设计:订阅信息由购买者手工录入或辅助登录选用(subscriptions表字段设计;密码不落库、token 会话内);登记时可粘贴 all_subscriptions JSON 预填;不做后台账号自动同步

4.4 参数被忽略的情况(实测)

请求 实际行为
/api/log/token?p=2 参数被忽略,仍返回最近 1000 条
/api/log/token?limit=5000 参数被忽略,仍返回最近 1000 条
/api/log/token?start_timestamp=1751328000 参数被忽略,仍返回最近 1000 条
/v1/dashboard/billing/usage?start_date=2025-07-01 参数被忽略

4.5 充值记录(2026-10-09 实测)

  • GET /api/user/topup/self?p=1&page_size=10——分页充值单;路径属 /api/user/*,预期 UserAuth()(账号登录态,非 sk-key)
  • 响应 { data: { page, page_size, total, items }, success };单条字段与样本:
字段 样本 含义
id 17 上游充值单 ID
user_id 6 账号
amount 1 平台计费金额(充值记账额;与 money 之间为管理员约定汇率,不标币种)
money 2.04 实付金额
trade_no USR6… 交易号
payment_method / payment_provider alipay / epay 渠道
create_time / complete_time Unix 秒 发起 / 入账完成
status success 单据状态
  • 无 quota_granted 字段——换得额度为派生(amount × quota_per_unit);登记不固化该列(topups表字段设计.md)
  • 展示时刻 = complete_time(平台列表即显示它);create_time 仅发起时刻——设计只存一条事件时间 paid_at = complete_time
  • 辅助登录代拉(与订阅同模式):UserAuth access_token、密码不落库;仅 p / page_size 分页、无时间参数——前端传统分页、可翻至尽头(不设页数硬上限);不做后台定时同步

5. 行为事实:写权限与 key 生命周期

  • sk-key 没有任何写接口:没有 POST/PUT/DELETE 能改 token 自身;无法通过 sk-key 重置 used_quota(没有"重置用量"接口)
  • 禁用 token 只改 status 字段:不重置 used_quota、不清零 remain_quota、不丢历史日志;解禁后三者原封不动
  • 唯一让 used_quota 归零的途径:删除 token 后新建(产生全新 Id/Key,旧日志按旧 token_id 关联,新 token 查不到旧日志)
  • 解禁保护:额度耗尽(Exhausted)且 RemainQuota ≤ 0 且非无限额度的 token 不能直接解禁,需先充值;已过期的 token 也不能直接解禁,需改过期时间

6. 源码参考

关注点 文件路径 关键函数/位置
路由注册 router/api-router.go usageRoute、logRoute 组
路由注册 router/dashboard.go:14-23 billing 路由组
路由注册 router/relay-router.go models 路由
API key 鉴权 middleware/auth.go:171 TokenAuthReadOnly()
API key 鉴权 middleware/auth.go TokenAuth() / SetupContextForToken
token 用量查询 controller/token.go GetTokenUsage
日志查询 controller/log.go:62 GetLogByKey
日志查询(model) model/log.go GetLogByTokenId(Limit 1000)
billing 查询 controller/billing.go:13 / :75 GetSubscription / GetUsage
显示开关 common/constants.go DisplayTokenStatEnabled
日志上限 common/constants.go MaxRecentItems = 1000
配额单位 common/constants.go QuotaPerUnit(默认 500000)
token 更新 model/token.go Update()(Select 不含 used_quota)
额度增减 model/token.go increaseTokenQuota / decreaseTokenQuota
日志类型常量 model/log.go LogTypeConsume = 2、LogTypeError = 5 等(刻意不用 iota)