Admin API

所有 Admin 端点挂在 /admin 前缀下,统一通过 Authorization: Bearer <token> 鉴权。Token 可以是两种之一:

  • Root token — 启动时从 GATEWAY_ROOT_TOKEN 环境变量读取,长期有效,拥有所有权限。运维侧使用。
  • Admin JWT — 通过 /admin/auth/login 用用户名密码换取,默认 TTL 12 小时。UI 登录场景使用。

错误响应统一为:

{ "error": { "code": "unauthorized", "message": "..." } }

下文每张表中的"权限":Any 表示两种 token 都可用。目前没有更细粒度的角色划分。


鉴权 /admin/auth

POST /admin/auth/login

用用户名密码换 JWT。仅在 admin.password_login: true 时启用。

请求:

{ "username": "alice", "password": "..." }

响应:

{
  "token": "<jwt>",
  "username": "alice",
  "expires_at": 1715760000
}

GET /admin/auth/me

返回当前 token 对应的 principal。

权限:Any。

响应:

{ "principal": "user", "username": "alice", "id": "adm_..." }

principal 取值为 rootuser

POST /admin/admins

创建一个 admin 用户(密码用 Argon2 哈希落库)。

权限:Any。

请求:

{ "username": "alice", "password": "strong-passphrase" }

字段约束:username 非空,password ≥ 6 位。不满足返回 400 bad_request

响应:

{ "id": "adm_...", "username": "alice" }

GET /admin/admins

列出所有 admin。

权限:Any。

响应:

[
  {
    "id": "adm_...",
    "username": "alice",
    "created_at": 1715000000,
    "last_login_at": 1715760000
  }
]

API Keys /admin/keys

POST /admin/keys

创建一个 Gateway API Key。明文只在响应里出现一次,落库的只是 BLAKE3 keyed hash。

权限:Any。

请求:

{
  "name": "my-app-prod",
  "env": "live",
  "project_id": "default",
  "scopes": ["proxy"],
  "expires_at": 1735689600
}
字段必填说明
name显示用,任意字符串。
envlivetest,只影响 key 的前缀(sk-gw-live- / sk-gw-test-),目前不参与认证、路由、限流、预算等任何逻辑。仅作为肉眼可见的标签,用于区分生产与测试 key(借鉴 Stripe 的命名约定)。
project_id默认 server.default_project_id
scopes默认 ["proxy"]。目前 scope 不参与执行,占位。
expires_atunix 秒。null 表示不过期。

响应:

{
  "id": "key_...",
  "name": "my-app-prod",
  "prefix": "sk-gw-live-",
  "last4": "a1b2",
  "secret": "sk-gw-live-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "created_at": 1715760000
}

GET /admin/keys

列出 Key(不返回明文)。

权限:Any。

查询参数:project_id(可选,按项目过滤)。

响应:

[
  {
    "id": "key_...",
    "project_id": "default",
    "name": "my-app-prod",
    "prefix": "sk-gw-live-",
    "last4": "a1b2",
    "status": "active",
    "created_at": 1715760000,
    "last_used_at": 1715800000,
    "expires_at": null,
    "origin": "admin"
  }
]

status 取值:active / revokedorigin 取值:admin(由本 API 创建)或 config(由 gateway_keys[] 预置,见 配置参考 > gateway_keys)。

DELETE /admin/keys/:id

撤销 Key(软删,status 变为 revoked)。originconfig 的 key 不能从这里撤销 —— 接口会返回 400 bad_request,需要在 YAML 里把这条记录删掉再 reload。

权限:Any。

响应:

{ "id": "key_...", "status": "revoked" }

请求日志 /admin/logs

GET /admin/logs

分页检索请求日志。

权限:Any。

查询参数(都可选):

参数类型说明
project_idstring按项目过滤。
gateway_key_idstring按 Key 过滤。
namespacestring按 URL namespace 过滤(对应 /v1/{namespace}/... 段)。
modelstring按模型名过滤(精确)。
statusstringok / gateway_error / upstream_error
from / tointunix 秒,时间范围。
limitint默认 50,上限 200。
cursorstring上一页响应里的 next_cursor

响应:

{
  "items": [ { "id": "log_...", "...": "..." } ],
  "next_cursor": "..."
}

GET /admin/logs/:id

返回单条日志的完整 JSON(包含请求/响应 body 摘要,大于 64KB 部分会被截断)。


配置只读 /admin/routes

GET /admin/routes

返回当前生效的 AppConfig(脱敏后),用于 UI 展示。配置改动会被自动重载,这里读到的总是最新版本。

权限:Any。


成本聚合 /admin/cost

GET /admin/cost

按维度聚合 token 用量与美元成本。

权限:Any。

查询参数:

参数说明
project_id限定项目。
from / to时间范围(unix 秒)。
group_bynamespace / model / gateway_key_id / day 之一(或逗号分隔的组合)。

响应:

{
  "rows": [
    {
      "key": "openai",
      "input_tokens": 12345,
      "output_tokens": 6789,
      "cost_usd": 0.12
    }
  ],
  "total_usd": 0.12
}

预算 /admin/budgets

GET /admin/budgets

返回当前所有预算的实时用量。

权限:Any。

响应:

[
  {
    "budget_id": "monthly-team",
    "name": "monthly-team",
    "period": "monthly",
    "period_start": 1714521600000,
    "amount_usd": 500.0,
    "used_usd": 87.3,
    "pct": 0.1746,
    "blocked": false
  }
]

blocked: true 表示已跨过 action: block 阈值,后续请求会被拒(HTTP 402)。


调用示例

用脚本批量创建 Key:

for i in 1 2 3; do
  curl -s -X POST http://localhost:8080/admin/keys \
    -H "Authorization: Bearer $GATEWAY_ROOT_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"name\":\"bot-$i\",\"env\":\"live\"}" \
    | jq '{name, secret}'
done