This repository has been archived on 2026-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
new-api-key-bench/docs/NewAPI-sk-key接口文档.md
T
skycurtain b2e0aa4a6c docs: 接口调研与设计文档
NewAPI sk-key 接口实证调研(计费参数/接口清单/坑记录)、交互设计定稿、实施计划。数据层与应用层后续按阶段提交。
2026-09-08 00:49:12 +08:00

431 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 |
### 关键开关:DisplayTokenStatEnabled
| 接口 | 受开关影响? |
|------|-------------|
| billing 接口(③④⑤⑥) | ✅ 受影响。开启 -> 返回 token 级额度;关闭 -> 回退到账号级额度(暴露整个账号余额) |
| `/api/usage/token`、`/api/log/token` | ❌ 不受影响,恒返回 token 级数据 |
**实测已确认当前平台开关为开启状态**(billing 接口返回的 `hard_limit_usd` 是 token 级占位值,非账号总额)。
开关位于后台:设置 -> 计费设置(Billing)-> "货币与显示"(Currency & Display)-> `Display Token Statistics`。仅管理员可改。
---
## 1. 接口清单总览
| 序号 | 方法 | 路径 | 鉴权 | 用途 |
|------|------|------|------|------|
| ① | 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/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 ÷ 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` | `QuotaPerUnit`(默认 500000) |
| token 更新 | `model/token.go` | `Update()`(Select 不含 used_quota) |
| 额度增减 | `model/token.go` | `increaseTokenQuota` / `decreaseTokenQuota` |
> 仓库地址:https://github.com/QuantumNous/new-api