Files
codex-proxy-rs/docs/api.md
T
2026-08-06 11:14:18 +08:00

18 KiB
Raw Permalink Blame History

Codex Proxy RS 接口

本文列出 v3 当前公开 HTTP 接口。路由事实以 backend/crates/gateway-api/src 中的 router 为准。

1. 鉴权与公共约定

客户端接口

所有 /v1/* 请求都使用管理端创建的 Client Key:

Authorization: Bearer sk_...

Client Key 固定绑定一个 Provider:openai 或 xai。同一次请求不会跨 Provider fallback。

管理接口

除登录、会话状态和登出外,所有 /api/admin/* 请求都需要以下任一鉴权方式:

  • 浏览器登录后得到的 cpr_admin_session Cookie;
  • x-api-key: <admin-api-key>。

请求无需自带 x-request-id;缺失时服务端自动生成 UUID 并在响应头回传同一 request ID。 api.request_id_header 可改变注入与回传的 header 名,管理端鉴权不依赖该名字。 管理端响应统一带 Cache-Control: no-store。

配置了 CORS 白名单 origin 时,跨域请求以凭据模式放行,仅允许 GET/POST 方法和 authorization、content-type、x-api-key 与 request ID 四个请求头,不使用通配符。

普通成功响应使用以下信封:

{
  "code": 200,
  "message": "OK",
  "data": {}
}

错误响应仍使用 code、message、data,其中 data 为 null。稳定业务码包括参数错误 40001、会话缺失 40101、登录凭据错误 40102、管理 API Key 错误 40103、资源不存在 40401、业务冲突 40901、内部错误 50001、上游失败 50201 和依赖不可用 50301。

管理写入一致性

Admin API 不暴露全局配置版本,mutation 请求也不要求客户端提供全局配置版本。会改变路由快照或安全配置的写入由后端在事务内推进内部配置 revision,并用于快照发布与审计。

2. 健康检查

方法 路由 鉴权 说明
GET /healthz 无 Core、Store 和后台任务健康时返回 204,否则返回 503

3. Responses 与模型目录

Responses HTTP body、WebSocket message 和 frame 不设置网关私有长度上限;协议可接受性由上游决定。

方法 路由 说明
POST /v1/responses OpenAI Responses JSON;stream=true 返回 SSE,否则返回完整 JSON
GET /v1/responses 通过 HTTP Upgrade 建立 Responses WebSocket
POST /v1/responses/review 使用同一 Responses 合同发起 review 子代理请求
GET /v1/models 返回当前 Client Key 所属 Provider 的可用公开模型;有两种响应形态,见下
GET /v1/models/catalog 返回 Codex 客户端使用的模型目录
GET /v1/models/{model_id}/info 返回 Codex 客户端使用的单模型信息
GET /v1/models/{model_id} 返回 OpenAI 兼容的单模型详情

GET /v1/models 默认返回 OpenAI 兼容列表 {"object": "list", "data": [...]};请求携带非空 client_version query 参数(Codex 客户端)时改为返回 Codex 专用目录合同 {"models": [...]}。

OpenAI 路径保留客户端 Responses wire 语义:请求 body 的未知字段和字段顺序保持不变(受控模型 映射除外),HTTP SSE 与 WebSocket 的上游业务事件字节原样转发,response ID 按 opaque 值处理而不 假设 UUID 或固定长度;OpenAI 上游错误 envelope 和允许下发的 opaque header 值也不由 canonical 观测结果重写。xAI 是 Grok wire 与 Responses wire 之间的协议转换层,转换只在 xAI Provider 内完成。 上游结构化错误的 message/code/type 会透传给客户端,其中内嵌的账号指纹 UUID 已脱敏。模型映射是 全局精确映射,未命中时模型名原样交给所属 Provider。

4. 管理员认证

方法 路由 请求 说明
POST /api/admin/auth/login { username?, password } 创建管理员会话并设置 Cookie
GET /api/admin/auth/status 无 返回当前 Cookie 是否已认证
POST /api/admin/auth/logout 无 删除当前会话并清除 Cookie

5. 账号

账号 API 使用统一路由,不存在 Provider Instance 或 Provider 专属账号路由。需要 Provider 的请求只接受 provider: "openai" | "xai"。

方法 路由 主要 query/body 说明
GET /api/admin/accounts page、pageSize、provider、search、status、排序字段 分页查询账号与汇总
GET /api/admin/accounts/detail accountId 查询账号详情、额度和本地用量
GET /api/admin/accounts/export accountIds、confirm=export_sensitive_accounts 显式导出最多 200 个账号的敏感 Provider 文档
POST /api/admin/accounts/import { provider, data } 导入或按上游身份更新账号
POST /api/admin/accounts/refresh { accountId } 手工刷新 OAuth credential(AT/RT),不刷新额度
POST /api/admin/accounts/rotate OpenAI rotation 字段 手工替换 OpenAI OAuth token
POST /api/admin/accounts/enable { provider, accountId } 启用账号
POST /api/admin/accounts/disable { provider, accountId } 禁用账号
POST /api/admin/accounts/delete { provider, accountIds } 批量删除 1–200 个账号
GET /api/admin/accounts/quota accountId 读取当前额度,不强制访问上游
POST /api/admin/accounts/quota/refresh { accountId } 访问 Provider 并刷新额度,同时同步额度所属状态
GET /api/admin/accounts/models accountId 优先读取该 Provider + 套餐的模型 cache,缺失时有限实时拉取
POST /api/admin/accounts/models/refresh { accountId } 强制拉取最新模型并覆盖 cache
GET /api/admin/accounts/connection-test accountId、modelId 通过 SSE 返回实时连接测试事件,不作为业务 Responses 用量记录
POST /api/admin/accounts/oauth/start { provider, name, accountId? } 创建 OpenAI 或 xAI OAuth flow;accountId 表示重新授权
POST /api/admin/accounts/oauth/complete { provider, flowId, callbackUrl } 消费 OAuth callback 并写入账号

账号列表支持以下稳定值:

  • provider: all、openai、xai;
  • status: active、expired、quota_exhausted、disabled、banned;
  • sortBy: email、status、planType、usage、lastUsedAt、expiresAt;
  • sortDirection: asc、desc。

导入的 data 必须是 JSON object,内部 schema 由目标 Provider 独占解释:

  • OpenAI 接受 OAuth 账号文档、账号 bundle 和 Agent Identity;
  • xAI 从单账号 object 或 accounts 数组中提取 OAuth token;包装中的代理、并发、优先级等字段不参与认证;
  • xAI 批量导入逐条独立校验:失败条目跳过并记录日志,不中断其余条目,仅当没有任何条目成功时整个导入才报错;
  • xAI API Key 不是受支持的账号 credential;
  • 导入仍会通过 Provider 的身份或刷新链路校验,不能只凭文件外形写入账号。

OpenAI 的 CPR 导出保持 OAuth 账号的既有字段;Agent Identity 账号则输出 authMode: "agentIdentity"、agentRuntimeId、agentPrivateKey 和可选的 taskId,不伪造 OAuth token 或过期时间。一个 sourceFormat: "cpr" 文档可以包含两种 认证类型,导入时按每个账号的认证模式分别解析。

{
  "sourceFormat": "cpr",
  "accounts": [{
    "id": "acct_...",
    "accountId": "...",
    "userId": "...",
    "authMode": "agentIdentity",
    "agentRuntimeId": "...",
    "agentPrivateKey": "...",
    "taskId": "..."
  }]
}

OpenAI rotation 请求字段为:

{
  "provider": "openai",
  "accountId": "acct_...",
  "accessToken": "...",
  "refreshToken": "..."
}

OAuth start 使用:

{
  "provider": "openai",
  "name": "account name",
  "accountId": null
}

重新授权已有账号时,start 请求仍携带 provider 和展示用 name,只额外提供目标 accountId; 客户端不得提交 credentialRevision、旧 token 身份或其他并发控制字段。complete 请求也不重复提交 accountId,后端通过 flowId 中保存的目标绑定完成授权。

OpenAI 身份、额度与状态

  • 文件导入只轻量解析 access token 的未验签 JWT payload:要求 exp 未过期且存在 chatgpt_account_id;不调用 JWKS 或 /wham/usage,也不做账号身份一致性比对。
  • 首次 OAuth 和重新授权保留回调 state、PKCE 与官方 token exchange。回调地址只承载 code/state, 不以 host/path 形式作为拒绝条件。
  • 账号文件导入和首次 OAuth 创建在 credential 提交后立即尝试一次额度观测。观测失败只记录告警, 不回滚已提交的账号;重新授权只轮换目标账号 credential,不隐式等同于手工额度刷新,也不更新既有 upstream account/user 或 OAuth principal。
  • OAuth pending flow 先取得带过期时间的独占 claim,只有账号事务提交成功后才消费。失败会释放 claim, 但上游 authorization code 本身通常只能交换一次;已完成过 token exchange 时应重新创建 OAuth flow。
  • GET /accounts/quota 只读取最后一次落库快照;POST /accounts/quota/refresh 才访问上游。access token 已过期时,额度刷新要求先走 credential 刷新或重新授权,不会拿过期 token 探测额度。
  • 成功额度观测会 revision-fenced 写入 quota,并在 active 与 quota_exhausted 等额度所属状态间同步; 不会清除 expired、banned 等 credential/封禁终态。额度接口的 401/403 也不足以判定 refresh token 永久失效,credential 终态只由 OAuth refresh 或身份校验链路写入。
  • 正常 Responses 请求会解析上游响应的 rate-limit headers,合并进同一 quota 快照并同步状态。Free、 K12 等套餐共用该状态机;套餐只参与账号展示和按套餐隔离的模型目录 cache,不存在 K12 专属额度路径。
  • 账号页没有定时静默轮询。手工额度刷新完成后页面会重新读取该账号;请求驱动或后台任务产生的状态 变化,需要下一次显式查询账号列表后才会显示。

6. Client Key

方法 路由 主要 query/body 说明
GET /api/admin/client-keys cursor、limit、search、sortBy、sortDirection 游标分页查询
POST /api/admin/client-keys/create 创建字段 创建绑定 Provider 的 Client Key
GET /api/admin/client-keys/reveal id 显式读取完整明文 Key
POST /api/admin/client-keys/update 更新字段 原子更新名称、Provider 和限额
POST /api/admin/client-keys/enable { id } 启用
POST /api/admin/client-keys/disable { id } 禁用
POST /api/admin/client-keys/delete { id } 删除

创建字段为 name、可选 label、providerKind、maxConcurrency、requestsPerMinute。更新请求再增加 id。创建和 reveal 响应会返回完整明文 Key,调用方必须立即安全保存。

7. 运行设置

方法 路由 说明
GET /api/admin/settings 读取运行设置
POST /api/admin/settings/update 原子替换全部运行设置
GET /api/admin/settings/admin-api-key 只返回管理 API Key 是否存在
POST /api/admin/settings/admin-api-key/delete 删除管理 API Key
POST /api/admin/settings/admin-api-key/regenerate 重新生成并一次性返回完整管理 API Key

设置更新字段包括:

modelMappings
refreshMarginSeconds
refreshConcurrency
maxConcurrentPerAccount
requestIntervalMs
rotationStrategy
usageRetentionDays
opsEventRetentionDays
auditRetentionDays

rotationStrategy 可取 smart、quota_reset_priority、round_robin、sticky。

8. 备份

全部备份端点位于 /api/admin/settings/backups/*,内部由独立 BackupService 承担,不并入设置用例。响应继续使用 AdminEnvelope,wire 字段 camelCase,Cache-Control: no-store。

方法 路由 请求 说明
GET /api/admin/settings/backups 无 读取存储配置(含明文 Secret)、验证状态与调度配置
POST /api/admin/settings/backups/storage/update S3 配置 更新存储配置;secretAccessKey 为空字符串会校验失败
POST /api/admin/settings/backups/storage/test 无 测试已保存的存储配置(Put/Head/Get/Delete 探针)
POST /api/admin/settings/backups/schedule/update 调度配置 更新 Cron、时区与保留策略
GET /api/admin/settings/backups/records 查询参数 分页查询备份记录
POST /api/admin/settings/backups/create { expiresInDays? } 创建手动备份,返回 202 Accepted;expiresInDays 为过期天数(0 或缺省表示不过期)
POST /api/admin/settings/backups/download-url { backupId } 创建 5 分钟有效预签名下载地址(仅 completed)
POST /api/admin/settings/backups/delete { backupId } 请求删除(进入 deleting,由 Worker 收敛硬删除)

读取设置响应(Secret 以明文返回,由前端掩码显示):

storageRevision, endpoint, region, bucket, accessKeyId, secretAccessKey, prefix,
forcePathStyle, verified, scheduleEnabled, cronExpression, scheduleTimezone,
retentionDays, retentionCount, nextRunAt, lastVerifiedAt, updatedAt

更新存储请求字段:

endpoint, region, bucket, accessKeyId, secretAccessKey, prefix, forcePathStyle

secretAccessKey 为空字符串会校验失败;由于 GET 会回传已保存的明文 Secret,保存时始终整体提交当前值。已有备份记录时,endpoint/region/bucket/forcePathStyle 不允许变化(存储身份锁定,409);只允许轮换凭据与修改 prefix。

更新调度请求字段:

scheduleEnabled, cronExpression, scheduleTimezone, retentionDays, retentionCount

cronExpression 为 5 段格式;retentionDays/retentionCount 为 0 表示禁用对应清理。启用计划前必须已保存完整存储配置且通过连接测试。

记录列表查询参数:

page, pageSize, status, trigger

status 可取 queued/dumping/uploading/completed/failed/deleting;trigger 可取 manual/scheduled。记录响应字段:

id, triggerKind, status, scheduledAt, objectKey, sizeBytes, sha256, attemptCount,
errorCode, errorMessage, startedAt, completedAt, expiresAt, createdAt, updatedAt

expiresAt 为创建时确定的手动过期时间;到期后由 Worker 自动清理(手动与计划备份均可设置)。

连接测试响应:

{ ok, stage, code, message }

stage 为 putObject/headObject/getObject/deleteObject。探测成功后以 storageRevision CAS 写入 lastVerifiedAt;测试期间配置变化则丢弃结果。

备份错误映射(AdminErrorCode 既有体系):

HTTP 场景
400 配置、Cron、时区或状态参数无效
404 备份记录不存在
409 已有活跃任务、状态冲突或存储身份锁定
502 S3 兼容服务返回无效或失败响应
503 PostgreSQL、pg_dump 或对象存储暂不可用

审计动作:backup.s3_config_updated、backup.s3_connection_tested、backup.schedule_updated、backup.created、backup.download_url_created、backup.delete_requested。审计详情与记录表均不保存 Secret、数据库连接串或预签名 URL query。

9. Dashboard、用量与错误

方法 路由 说明
GET /api/admin/dashboard/summary Dashboard 汇总;支持 kind、startTime、endTime
GET /api/admin/dashboard/trend Dashboard 趋势;`kind=usage
GET /api/admin/usage/records 请求记录分页列表
GET /api/admin/usage/records/detail 按 id 查询请求详情
GET /api/admin/usage/records/summary 当前筛选条件的请求汇总
GET /api/admin/usage/insights/overview 用量、成本与成功率洞察
GET /api/admin/usage/insights/diagnostics 按维度聚合诊断
GET /api/admin/operations/errors 运维错误分页列表

用量查询可组合页码/游标、时间范围、Provider、Client Key、账号、模型、route、transport、状态码、 request/response/upstream ID、outcome 与搜索文本。诊断 dimension 可取 model、account、 apiKey、provider、transport、failureClass、status。

汇总与洞察中的请求数与 outcome 分布覆盖筛选范围内全部请求;token、缓存、延迟与成本聚合仅统计 已完整交付客户端的成功响应。

OpenAI 的 serviceTier 只接受上游响应生命周期事件确认的实际 response.service_tier;请求里的 期望档位只保留在 request summary,不能冒充响应事实。计费展示把 priority/fast 映射为 Fast, flex 映射为 Flex,缺失或 default 映射为 Default;未知非空值原样展示。Fast 优先使用模型的 priority 价格,缺少专用价格时回退到标准价格的 2.00x;Flex 为 0.50x,Default 为 1.00x。

10. 版本、更新与重启

方法 路由 主要 query/body 说明
GET /api/admin/system/version 无 当前构建、部署模式和可用更新
GET /api/admin/system/update/detail `refresh=true false`
GET /api/admin/system/update/events 无 SSE 更新事件流
POST /api/admin/system/update 可选 { targetVersion } 开始在线更新
GET /api/admin/system/update/status 无 查询当前更新或回滚状态
POST /api/admin/system/rollback 无 回滚到保留的上一版本
POST /api/admin/system/restart 无 请求进程重启

在线更新仅在当前部署模式、Release 资产和进程重启能力都满足要求时可用,且只在同一 major 版本内 提供:跨大版本目标会以 40901 冲突拒绝,需按发布说明手动迁移。仓库发版流程见 部署文档 与根目录 README。