# NewAPI sk-key 查询接口文档 > 基于源码实证调研(QuantumNous/new-api),整理所有可通过 `sk-` API key 直接访问的查询接口。 > > 调研日期:2025-07 月 · 源码版本:main 分支 --- ## 0. 通用说明 ### 认证方式 所有接口均使用 API key 鉴权,在请求头中携带: ``` Authorization: Bearer sk-xxxxxxxxxxxx ``` **不需要**账号登录态(access token / session)。这是拼车场景能成立的关键前提。 ### BaseURL 即 NewAPI 站点地址,例如 `https://your-friend-domain.com`。所有路径前不带多余前缀,直接拼接。 ### 两种鉴权中间件 | 中间件 | 说明 | |--------|------| | `TokenAuth()` | 标准版:校验 key 有效、未过期、有剩余额度。过期或耗尽的 key 会被拒绝。 | | `TokenAuthReadOnly()` | 宽松版:只校验 key 存在且用户未封禁。**即使 key 已过期、已禁用、额度耗尽也能查询**。 | > `/api/usage/token` 和 `/api/log/token` 用的是 `TokenAuthReadOnly()`,所以伙伴的 key 即使用完了,仍能查到自己的用量记录。 ### 已确认的换算参数 | 参数 | 值 | 来源 | |------|-----|------| | `QuotaPerUnit` | 500000 | 实测验证:接口① `total_used` ÷ 500000 = 接口④ `total_usage` ÷ 100 | **此值是 NewAPI 的默认值(源码 `common/constants.go:22`:`var QuotaPerUnit = 500 * 1000.0 // $0.002 / 1K tokens`),并非硬编码定律**: - 它是 `var` 且挂入 OptionMap(`model/option.go:166`),站长可在后台修改(`model/option.go:605` 会用数据库值覆盖) - 接口①④交叉实测吻合的原因:billing 接口内部就是拿 quota `÷ QuotaPerUnit` 换算(`controller/billing.go:50`),同一常量自证,**吻合验证不了管理员是否改过此值** - **正确做法:换算比率不硬编码,从 `/api/status` 的 `quota_per_unit` 字段读取**(见接口⓪),启动时拉取并定期校验,站点改配置后工具自动跟随 > `500000` 的设计来由:NewAPI(继承自 One API)以 OpenAI 早期基准定价 **$0.002 / 1K tokens** 为锚点,内部用整数 quota 计费避免浮点误差,1 quota = $0.000002,反推 1 美元 = 500,000 quota。 ### 关键开关:DisplayTokenStatEnabled | 接口 | 受开关影响? | |------|-------------| | billing 接口(③④⑤⑥) | ✅ 受影响。开启 -> 返回 token 级额度;关闭 -> 回退到账号级额度(暴露整个账号余额) | | `/api/usage/token`、`/api/log/token` | ❌ 不受影响,恒返回 token 级数据 | **实测已确认当前平台开关为开启状态**(billing 接口返回的 `hard_limit_usd` 是 token 级占位值,非账号总额)。 开关位于后台:设置 -> 计费设置(Billing)-> "货币与显示"(Currency & Display)-> `Display Token Statistics`。仅管理员可改。 --- ## 1. 接口清单总览 | 序号 | 方法 | 路径 | 鉴权 | 用途 | |------|------|------|------|------| | ⓪ | GET | `/api/status` | **无(完全公开)** | 站点配置与计费参数(含 `quota_per_unit`),工具校准换算比率的依据 | | ① | GET | `/api/usage/token` | TokenAuthReadOnly | 查 token 的累计已用/剩余/总额(原始 quota) | | ② | GET | `/api/log/token` | TokenAuthReadOnly | 查该 key 最近 1000 条调用日志 | | ③ | GET | `/v1/dashboard/billing/subscription` | TokenAuth | 查总额度上限(OpenAI 兼容,美元) | | ④ | GET | `/v1/dashboard/billing/usage` | TokenAuth | 查累计已用(OpenAI 兼容,美分) | | ⑤ | GET | `/dashboard/billing/subscription` | TokenAuth | 同 ③,不带 /v1 前缀 | | ⑥ | GET | `/dashboard/billing/usage` | TokenAuth | 同 ④,不带 /v1 前缀 | | ⑦ | GET | `/v1/models` | TokenAuth | 列出可用模型(OpenAI 格式) | | ⑧ | GET | `/v1/models/:model` | TokenAuth | 查单个模型详情 | | ⑨ | GET | `/v1beta/models` | TokenAuth | 列出可用模型(Gemini 格式) | | ⑩ | GET | `/v1beta/openai/models` | TokenAuth | 列出可用模型(OpenAI 格式) | > ③和⑤是同一个接口,④和⑥是同一个接口,只是路径前缀不同(为兼容不同客户端写法)。测一组即可。 > > ⑦~⑩是模型列表接口,与用量统计无关,列出仅为完整覆盖。 --- ## 2. 用量/额度查询接口详解 ### ⓪ GET `/api/status` - 站点配置与计费参数(完全公开) **鉴权**:无。挂载于 `router/api-router.go:26`,在鉴权中间件组之外,任何人(不持有任何 key)可直接访问。本清单中唯一无需凭证的接口。 **请求参数**:无 **请求示例**: ``` GET /api/status ``` **返回结构**(源码:`controller/misc.go:44` -> `GetStatus`):外层为 `{ success, message, data }`,`data` 含 60+ 字段(版本、登录方式、前端模块开关、公告等)。**与本项目相关的计费字段**: | 字段 | 类型 | 说明 | 实测值(2026-09-09) | |------|------|------|------| | `quota_per_unit` | float | **QuotaPerUnit 当前生效值**。quota ÷ 该值 = 美元。管理员可改,工具不得硬编码 | `500000` | | `quota_display_type` | string | 站点额度展示模式:`USD` / `CNY` / `TOKENS`。影响 billing 接口(③④)的语义 | `"USD"` | | `usd_exchange_rate` | float | USD→CNY 展示汇率(`quota_display_type=CNY` 时 billing 接口用它换算) | `6.8` | | `display_in_currency` | bool | 是否以货币展示额度(旧字段,兼容保留) | `true` | | `custom_currency_symbol` | string | 自定义货币符号(`¤` = 未自定义) | `"¤"` | | `custom_currency_exchange_rate` | float | 自定义货币汇率 | `1` | | `price` | float | 充值价格(人民币/单位),站点充值汇率相关 | `6.8` | | `version` | string | NewAPI 版本号 | `"v1.0.0-rc.35"` | **对本项目的意义**: 1. **校准换算比率**:`quota_per_unit` 是工具换算美元的唯一权威来源——管理员改配置后,工具启动时拉取 + 定期校验即可自动跟随,不会算错 2. **感知展示模式切换**:若管理员把 `quota_display_type` 切到 `CNY` 或 `TOKENS`,billing 接口(③④)返回的数字语义会变(CNY 是先 ÷QuotaPerUnit 再 ×`usd_exchange_rate`;TOKENS 直接返回 token 数),工具可提前探测到,避免拿旧逻辑解析新语义 3. **零成本**:完全公开、无鉴权、无调用门槛,可放心定期轮询 **注意事项**: - 返回字段很多且含大量前端 UI 配置(`HeaderNavModules`、`SidebarModulesAdmin` 等),解析时只取计费相关字段,其余忽略 - 字段集合随版本演进(如开启公告开关会追加 `announcements`),解析需容忍未知字段 - 该接口不泄露敏感信息(secret 类 OptionMap 键已被 NewAPI 过滤),这也是它敢完全公开的原因 --- ### ① GET `/api/usage/token` - token 级用量汇总 **鉴权**:`TokenAuthReadOnly()`(宽松版,key 过期/耗尽也能查) **请求参数**:无 **请求示例**: ``` GET /api/usage/token Authorization: Bearer sk-xxxx ``` **返回结构**(源码:`controller/token.go` -> `GetTokenUsage`): ```json { "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 创建以来累计,非当月。换算美元:`total_used ÷ 500000` | | `total_available` | int | 剩余 = total_granted − total_used。无限额度时为负数,无实际意义 | | `unlimited_quota` | bool | 是否无限额度。true 时 total_granted/total_available 无实际意义 | | `model_limits` | object | 模型限制(map) | | `model_limits_enabled` | bool | 是否启用模型限制 | | `expires_at` | int | 过期时间(Unix 秒),0 = 永不过期 | **注意事项**: - `total_used` 是**累计值**,从 key 创建以来累计,不是当月用量。 - 额度单位是**原始 quota 整数**,需自行除以 `QuotaPerUnit`(默认 500000)换算美元。 - 禁用再解禁不会重置 `total_used`(源码验证:`Update()` 的 `.Select(...)` 列表不含 `used_quota`)。 --- ### ② GET `/api/log/token` - token 级调用日志 **鉴权**:`TokenAuthReadOnly()` **请求参数**:无(不支持任何 query 参数) **请求示例**: ``` GET /api/log/token Authorization: Bearer sk-xxxx ``` **返回结构**(源码:`controller/log.go:62` -> `GetLogByKey`): ```json { "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": "req_xxx", "upstream_request_id": "", "other": "" } ] } ``` **字段说明**: | 字段 | 类型 | 说明 | |------|------|------| | `created_at` | int | 调用时间(Unix 秒)- **客户端可据此筛当月** | | `type` | int | 日志类型:2=消费,5=错误,1=充值等 | | `model_name` | string | 调用的模型名 | | `quota` | int | 本次消耗的 quota(换算美元:`quota ÷ 500000`) | | `prompt_tokens` | int | 输入 token 数 | | `completion_tokens` | int | 输出 token 数 | | `use_time` | int | 耗时(秒) | | `is_stream` | bool | 是否流式 | | `channel_name` | string | 渠道名(普通用户会被清空) | **关键限制**: - **硬上限 1000 条**:固定返回最近 1000 条日志(`Limit(common.MaxRecentItems)`,`MaxRecentItems = 1000`,定义于 `common/constants.go`)。 - **不支持任何请求参数**:`GetLogByKey` 不读任何 `c.Query()`,没有分页(page/limit/offset),没有时间过滤(start_timestamp/end_timestamp)。 - **固定按 `id desc` 排序**:即最新 1000 条。 - **超过 1000 条的旧记录无法获取**:无法翻页,无法扩大 limit。 - **当月调用超 1000 次时,此接口无法覆盖完整当月数据**。 --- ### ③ GET `/v1/dashboard/billing/subscription` - 总额度上限 **鉴权**:`TokenAuth()` **请求参数**:无 **请求示例**: ``` GET /v1/dashboard/billing/subscription Authorization: Bearer sk-xxxx ``` **返回结构**(源码:`controller/billing.go:13` -> `GetSubscription`): ```json { "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` | float | **总额度上限**(美元)。无限额度 key 返回 `100000000`(占位值,无实际意义) | | `soft_limit_usd` | float | 软上限(同 hard_limit_usd) | | `system_hard_limit_usd` | float | 系统上限(同 hard_limit_usd) | | `access_until` | int | token 过期时间(Unix 秒),0 = 永不过期 | **注意事项**: - 受 `DisplayTokenStatEnabled` 开关影响。开启时返回 token 级额度;关闭时返回账号级额度(会暴露整个账号余额)。 - 无限额度 key 返回 `100000000`(一亿)作为占位值,无参考意义。 - 受 `quota_display_type` 影响:USD 模式直接是美元;CNY 模式会做货币转换;Tokens 模式是原始 token 数。 --- ### ④ GET `/v1/dashboard/billing/usage` - 累计已用 **鉴权**:`TokenAuth()` **请求参数**:无 **请求示例**: ``` GET /v1/dashboard/billing/usage Authorization: Bearer sk-xxxx ``` **返回结构**(源码:`controller/billing.go:75` -> `GetUsage`): ```json { "object": "list", "total_usage": 134683.8914 } ``` **字段说明**: | 字段 | 类型 | 说明 | |------|------|------| | `total_usage` | float | **累计已用**(单位:**美分**)。换算美元:`total_usage ÷ 100` | **实测验证**: ``` total_usage = 134683.8914 美分 ÷ 100 = 1346.84 美元 与接口① total_used(673419457) ÷ 500000 = 1346.84 美元 完全吻合 ``` **注意事项**: - `total_usage` 是**累计值**(从 key 创建至今),不是当月用量。 - 受 `DisplayTokenStatEnabled` 开关影响(开启时为 token 级)。 - 受 `quota_display_type` 影响(USD 模式才是美元,否则需另行换算)。 - `hard_limit_usd`(接口③)− `total_usage ÷ 100`(接口④)= 剩余额度(仅有限额 key 有意义)。 --- ## 3. 模型列表接口(与用量无关) > 以下接口 sk-key 可访问,但返回的是模型列表,与用量统计无关。列出仅为完整覆盖。 ### ⑦ GET `/v1/models` 返回当前 key 可用的模型列表,OpenAI 兼容格式。 ```json { "object": "list", "data": [ { "id": "gpt-4o", "object": "model", "created": 1686935000, "owned_by": "openai" } ] } ``` ### ⑧ GET `/v1/models/:model` 返回单个模型详情。将 `:model` 替换为模型名,如 `/v1/models/gpt-4o`。 > **已知限制**:此接口与 `/v1/models` 数据源不同。`/v1/models` 查数据库 `abilities` 表(反映渠道实际配置的模型),而此接口查代码内硬编码的静态模型列表(`openAIModelsMap`)。当渠道配了新模型或自定义模型名但代码未收录时,会出现"列表里有但单查返回 `model_not_found`"的现象。不影响实际模型调用。 ### ⑨ GET `/v1beta/models` 返回模型列表(Gemini 兼容格式)。 ### ⑩ GET `/v1beta/openai/models` 返回模型列表(OpenAI 格式,Gemini 路由下)。 --- ## 4. 确认不存在的接口(排除清单) 以下接口在源码中**不存在**或**不可用 sk-key 访问**,测试时应返回 404 或 401: ### 4.1 不存在的接口(返回 404) | 路径 | 状态 | |------|------| | `/v1/usage` | 不存在 | | `/v1/quota` | 不存在 | | `/api/token/self` | 不存在 | ### 4.2 存在但需要登录态的接口(sk-key 访问返回 401) 这些接口支持时间范围查询和 `token_name` 过滤,但**必须用账号登录态**(access token + `New-Api-User` header),sk-key 无法访问: | 路径 | 鉴权 | 能力 | |------|------|------| | `/api/log/self` | `UserAuth()` | 支持 `start_timestamp`、`end_timestamp`、`token_name` 过滤,返回日志明细 | | `/api/log/self/stat` | `UserAuth()` | **支持时间范围 + token_name,返回 quota 汇总**(调 `SumUsedQuota`) | | `/api/data/self` | `UserAuth()` | 按日聚合的看板数据 | | `/api/token/` (GET/POST/PUT/DELETE) | `UserAuth()` | token 的增删改查 | | `/api/user/self` | `UserAuth()` | 用户自身信息 | > **特别说明**:`/api/log/self/stat` 是 NewAPI 中最适合算"当月用量"的接口--传当月起止时间 + `token_name` 即可返回该 key 当月消耗的 quota 总和。但它需要登录态,是拼车场景下"当月用量"难以纯客户端实现的核心障碍。 ### 4.3 参数被忽略的情况 | 请求 | 实际行为 | |------|---------| | `/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` | 参数被忽略 | --- ## 5. 用量换算速查 ### 核心换算公式 ``` 原始 quota ÷ quota_per_unit(/api/status 实时读取,当前站点值 500000)= 美元 ``` ### 实测数据验证 | 来源 | 原始值 | 换算 | 结果 | |------|--------|------|------| | 接口① `total_used` | 673,419,457 quota | ÷ 500000 | 1346.84 美元 | | 接口④ `total_usage` | 134,683.8914 美分 | ÷ 100 | 1346.84 美元 | 两者完全吻合,确认 `QuotaPerUnit = 500000`。 --- ## 6. 关键限制总结 ### 6.1 时间维度 - **所有 sk-key 接口返回的用量都是累计值**(从 key 创建至今),没有任何接口直接返回"当月用量"。 - 唯一带时间戳的是 `/api/log/token`,但硬限 1000 条且不支持时间过滤。 - 支持时间范围的接口(`/api/log/self`、`/api/log/self/stat`)需要登录态,sk-key 无法访问。 ### 6.2 日志条数 - `/api/log/token` 硬上限 **1000 条**(`MaxRecentItems = 1000`,定义于 `common/constants.go`)。 - 不支持分页、不支持时间过滤、不支持改变 limit。 - 月调用量超过 1000 次时,此接口无法覆盖完整当月数据。 ### 6.3 写操作 - **sk-key 没有任何写接口**(没有 POST/PUT/DELETE 能改 token 自身)。 - token 的增删改查(`/api/token/`)全部需要登录态 `UserAuth()`。 - 无法通过 sk-key 重置 `used_quota`(没有"重置用量"接口,`Update()` 的 Select 列表不含 `used_quota`)。 ### 6.4 禁用/解禁行为 - 禁用 token 只改 `status` 字段,**不重置 `used_quota`**,不清零 `remain_quota`,不丢历史日志。 - 解禁后 `used_quota`、`remain_quota`、历史日志全部原封不动。 - 唯一让 `used_quota` 归零的途径是**删除 token 后新建**(产生全新 Id/Key,旧日志按旧 token_id 关联,新 token 查不到旧日志)。 - 解禁保护:额度耗尽(`Exhausted`)且 `RemainQuota ≤ 0` 且非无限额度的 token 不能直接解禁,需先充值;已过期的 token 也不能直接解禁,需改过期时间。 --- ## 7. 源码参考 | 关注点 | 文件路径 | 关键函数/位置 | |--------|---------|--------------| | 路由注册 | `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` | `GetSubscription` | | billing 查询 | `controller/billing.go:75` | `GetUsage` | | 显示开关 | `common/constants.go` | `DisplayTokenStatEnabled` | | 日志上限 | `common/constants.go` | `MaxRecentItems = 1000` | | 配额单位 | `common/constants.go:22` | `QuotaPerUnit`(var,默认 500000,`// $0.002 / 1K tokens`,可被 OptionMap 覆盖) | | 配额单位(覆盖入口) | `model/option.go:605` | `case "QuotaPerUnit"` 运行时改写 | | 站点配置暴露 | `controller/misc.go:44` + `router/api-router.go:26` | `GetStatus`(`/api/status`,无鉴权,含 `quota_per_unit`) | | token 更新 | `model/token.go` | `Update()`(Select 不含 used_quota) | | 额度增减 | `model/token.go` | `increaseTokenQuota` / `decreaseTokenQuota` | > 仓库地址:https://github.com/QuantumNous/new-api