15 KiB
API 接口格式参考
本文档是 CLAUDE.md 中 API 接口规范的详细参考资料,包含完整的 JSON 示例、响应格式、错误类型映射等。开发时按需查阅。
统一响应格式详细示例
适用范围:/api/admin/*、/api/tenant/*、/api/payment/*、/api/open/*、/api/status。
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
code |
int | 0 = 成功,非 0 = 错误。标准 HTTP 错误直接用状态码(400/401/403/404/409/500),业务错误用 >= 10000 的自定义码 |
message |
string | 用户可读的中文提示。成功时固定 "ok",错误时描述具体原因,禁止暴露技术细节 |
data |
any | 成功时为业务数据(对象/数组/字符串),错误时为 null |
request_id |
string | 每个请求的唯一标识,贯穿全链路,用于日志追踪 |
响应示例
// 成功(HTTP 200)
{"code": 0, "message": "ok", "data": {"id": 1, "name": "张三"}, "request_id": "req_abc123"}
// 参数错误(HTTP 400)
{"code": 400, "message": "用户名不能为空", "data": null, "request_id": "req_def456"}
// 业务错误(HTTP 422)
{"code": 10001, "message": "余额不足", "data": null, "request_id": "req_ghi789"}
data 字段格式规范
| 接口类型 | data 结构 | 示例 |
|---|---|---|
| 分页列表 | {list, total, page, page_size} |
{"list": [...], "total": 100, "page": 1, "page_size": 20} |
| 不分页列表 | {list} |
{"list": [...]} |
| 创建资源 | {id} |
{"id": 42} |
| 资源详情 | 直接返回对象 | {"id": 1, "name": "张三", ...} |
| 更新/删除 | null |
null |
规则:
- 列表数据的数组字段名统一用
list,禁止使用data、items、records等其他名称 - 分页列表必须返回
total(总条数)和page(当前页码),可选返回page_size - 创建操作只返回新资源的
id,不返回完整对象 - 更新/删除操作返回
null,前端通过 HTTP 200 +code: 0判断成功 - 如果 list 内部可以为空,但是不能有 null 出现
HTTP 状态码映射规则
| 业务场景 | HTTP 状态码 | code 值 | 说明 |
|---|---|---|---|
| 成功 | 200 | 0 |
请求处理成功 |
| 参数校验失败 | 400 | 400 |
请求体格式错误、必填字段缺失、值不合法 |
| 未认证 | 401 | 401 |
Token 缺失、过期、无效 |
| 无权限 | 403 | 403 |
已认证但无权访问该资源 |
| 资源不存在 | 404 | 404 |
查询的对象不存在 |
| 请求频率超限 | 429 | 429 |
触发限流 |
| 业务规则错误 | 422 | >= 10000 |
业务逻辑不满足,使用自定义错误码(见 consts.go) |
| 服务器内部错误 | 500 | 500 |
未预期的异常 |
业务错误码定义(>= 10000)
业务错误码定义在 internal/consts/consts.go 中,每个错误码有对应的中文消息常量。新增业务错误时必须同时在 consts.go 中添加 Code 和 Msg 常量。
| 错误码 | 常量名 | 默认消息 |
|---|---|---|
| 10001 | CodeInsufficientBalance |
余额不足 |
| 10002 | CodeQuotaExceeded |
额度已用完 |
| 10003 | CodeChannelUnavailable |
没有可用的渠道 |
| ... | 更多见 consts.go |
... |
大模型代理接口格式(/v1/*、/v1beta/*、/v2/*、/suno/*)
已注册的代理端点
| 方法 | 路径 | 功能 | 请求格式 | 流式支持 |
|---|---|---|---|---|
| POST | /v1/chat/completions |
Chat Completions | OpenAI | SSE |
| POST | /v1/completions |
Text Completions | OpenAI | SSE |
| POST | /v1/embeddings |
文本向量 | OpenAI | 否 |
| POST | /v1/images/generations |
图像生成 | OpenAI | 否 |
| POST | /v1/images/edits |
图像编辑 | OpenAI | 否 |
| POST | /v1/messages |
Claude Messages | Claude | SSE |
| POST | /v1/responses |
OpenAI Responses | OpenAI | SSE |
| POST | /v1/audio/speech |
语音合成 | OpenAI | 否 |
| POST | /v1/audio/transcriptions |
语音转文字 | OpenAI | 否 |
| POST | /v1/audio/translations |
语音翻译 | OpenAI | 否 |
| POST | /v1/rerank |
重排序 | OpenAI | 否 |
| POST | /v1/moderations |
内容审核 | OpenAI | 否 |
| GET | /v1/models |
模型列表 | — | 否 |
| GET | /v1/models/{model_id} |
模型详情 | — | 否 |
| GET | /v1/realtime |
实时对话(WebSocket) | OpenAI | WebSocket |
| POST | /v1/video/generations |
视频生成(异步任务) | 自定义 | 否 |
| GET | /v1/video/generations/{task_id} |
视频生成任务查询 | — | 否 |
| POST | /v1/videos |
OpenAI Videos 视频生成(multipart/JSON) | OpenAI | 否 |
| GET | /v1/videos/{video_id} |
OpenAI Videos 任务查询 | — | 否 |
| GET | /v1/videos/{video_id}/content |
OpenAI Videos 成品下载 | — | 否 |
| DELETE | /v1/videos/{video_id} |
OpenAI Videos 任务删除(终态软删) | — | 否 |
| GET | /v1beta/models |
Gemini 模型列表 | Gemini | 否 |
| GET | /v1beta/models/{model} |
Gemini 模型详情 | Gemini | 否 |
| POST | /v1beta/models/{model} |
Gemini 内容生成 | Gemini | SSE |
| POST | /suno/submit/{action} |
Suno 音乐生成提交 | 自定义 | 否 |
| POST | /suno/fetch |
Suno 批量查询 | 自定义 | 否 |
| GET | /suno/fetch/{task_id} |
Suno 任务查询 | — | 否 |
| POST | /v2/video_generation |
MiniMax H3 视频生成(官方协议 v2) | MiniMax | 否 |
| GET | /v2/query/video_generation/{task_id} |
MiniMax H3 任务查询(v2) | — | 否 |
| DELETE | /v2/video_generation/{task_id} |
MiniMax H3 任务取消(仅排队中,v2) | — | 否 |
| POST | /v1/video_generation |
MiniMax Hailuo 视频生成(官方协议 v1,四形态共用) | MiniMax | 否 |
| GET | /v1/query/video_generation?task_id= |
MiniMax Hailuo 任务查询(v1,query 参数) | — | 否 |
MiniMax 官方视频协议(/v2/*,MiniMax-H3/H3-Max)
对 MiniMax v2 视频协议的原生接入:官方 SDK 把 base_url 指向网关即可直连。协议规格见 docs/modeldocs/minimax/video/。
提交 POST /v2/video_generation(Bearer 平台 API Key):
{
"model": "MiniMax-H3",
"content": [{ "type": "text", "text": "海浪拍打礁石,慢镜头。" }],
"resolution": "768P",
"duration": 6,
"ratio": "16:9"
}
model/content(含非空 text 项)/resolution/duration四项必填;ratio文生视频时必填(不能为adaptive)callback_url会被剥离:网关按自身任务体系轮询计费,上游回调携带的上游 task_id 与网关公开 ID 不互通- 提交响应为官方形态:
{"task_id": "task_xxx"}(网关公开任务 ID,非上游 ID)
查询 GET /v2/query/video_generation/{task_id} → {"task": {官方 VideoTask}}:
状态机 queued/running/succeeded/failed(上游取消的任务回放为 failed)。content.url 为上游限时直链;
usage/resolution/duration/ratio 从最近一次上游查询响应回放,任务提交后首拍轮询前(≤15s)可能缺失。
取消 DELETE /v2/video_generation/{task_id}:仅支持取消排队中(queued)的任务,取消结果以远程返回为准——
网关调用上游 DELETE,上游确认 action=cancelled 才向客户端返回成功
({"task_id": "...", "action": "cancelled", "status": "cancelled"});上游拒绝时(如任务已进入 running)
原样透传上游错误。不支持删除任务记录(终态任务不可删,软删也不做,任务数据保留用于计费与审计;错误码 task_not_cancellable)。
取消确认后本地状态由轮询循环在下一拍(≤15s)对账收敛为 failed,预扣随之退款。
错误响应为 OpenAI 风格 OaiError({"error": {"type": "...", "message": "..."}}),与官方 v2 一致。
OpenAI 协议互通:同一渠道下 POST /v1/videos(OpenAI Videos 协议)与 POST /v1/video/generations(通用任务体)可直接调用 MiniMax 视频模型(H3 与 Hailuo 系列按模型自动分派 v2/v1 上游协议)。size 只借 OpenAI 协议的字段形态、值原样透传不换算——请直接传目标供应商的原生分辨率词汇(H3:768P/2K/480P;Hailuo 2.x:768P/1080P);非官方档位值会原样送达上游(上游 400 则任务提交失败、预扣全额退款)。时长取 seconds/duration/metadata.duration(缺省 6 秒),input_reference/images[0] 作为首帧图(v1 转为 first_frame_image),纯文生视频时 v2 ratio 默认 16:9。
MiniMax 官方视频协议 v1(/v1/video_generation,Hailuo 系列)
Hailuo 2.x 及旧型号(T2V/I2V/S2V-01,传入即转发不拦截)走 v1 扁平字段协议:
- 提交
POST /v1/video_generation:文生(prompt必填)/ 图生(first_frame_image必填,支持 URL 或 data URI)/ 首尾帧(last_frame_image,仅 Hailuo-02)/ 主体参考(subject_reference,S2V-01)四形态共用;duration(默认 6,768P 支持 10)/resolution(Hailuo 2.x 默认768P,旧型号默认720P)可选;prompt_optimizer/fast_pretreatment/aigc_watermark透传;callback_url剥离。响应为官方{task_id, base_resp}形态(task_id 为网关公开 ID) - 查询
GET /v1/query/video_generation?task_id=:官方{task_id, status, file_id, video_width, video_height, base_resp}形态,状态机Preparing/Queueing/Processing/Success/Fail;增补字段download_url(网关轮询时经官方 files/retrieve 二跳解析的限时直链,官方查询响应无此字段)与error(失败原因) - 成品二跳由网关代取:官方流程「file_id → GET /v1/files/retrieve → download_url」在轮询时链式完成,
download_url落任务记录并回放到查询响应;不暴露 files/retrieve 代理端点 - 取消/删除:v1 上游无此能力,端点不提供(v2 的 DELETE 端点对 v1 任务返回 400)
- v1 无 usage 返回,计费按请求规格(per_second 矩阵 × 时长),与 v2 口径一致
OpenAI 格式端点响应
非流式响应直接透传上游 JSON,典型结构:
// Chat Completions 响应
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "Hello!"},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
}
// Embeddings 响应
{
"object": "list",
"data": [
{"object": "embedding", "embedding": [0.1, 0.2, ...], "index": 0}
],
"model": "text-embedding-3-small",
"usage": {"prompt_tokens": 5, "total_tokens": 5}
}
流式响应使用 SSE(Server-Sent Events),Content-Type: text/event-stream:
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":9,"completion_tokens":12,"total_tokens":21}}
data: [DONE]
OpenAI 格式错误响应:
{
"error": {
"type": "invalid_request_error",
"message": "余额不足,请联系管理员充值",
"param": null,
"code": null
}
}
错误类型映射:
| 平台错误场景 | error.type | HTTP 状态码 |
|---|---|---|
| 认证失败(API Key 无效) | authentication_error |
401 |
| 权限不足(Key 无权访问模型) | permission_error |
403 |
| 余额不足 / 额度耗尽 | insufficient_quota |
402 |
| 模型不存在 / 参数错误 | invalid_request_error |
400 |
| 请求频率超限 | rate_limit_error |
429 |
| 没有可用渠道 | server_error |
503 |
| 上游供应商错误 | 原样透传上游错误类型 | 上游状态码 |
| 平台内部错误 | internal_error |
500 |
Claude 格式端点响应(/messages)
非流式响应:
{
"id": "msg_abc123",
"type": "message",
"role": "assistant",
"content": [{"type": "text", "text": "Hello!"}],
"model": "claude-sonnet-4-20250514",
"stop_reason": "end_turn",
"usage": {
"input_tokens": 25,
"output_tokens": 10
}
}
流式响应(SSE):
event: message_start
data: {"type":"message_start","message":{"id":"msg_abc123","type":"message","role":"assistant","content":[],"model":"claude-sonnet-4-20250514","usage":{"input_tokens":25,"output_tokens":0}}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello!"}}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":10}}
event: message_stop
data: {"type":"message_stop"}
Claude 格式错误响应:
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "余额不足,请联系管理员充值"
}
}
Gemini 格式端点响应(/v1beta/models/*)
使用 Google Gemini API 原生格式透传,错误格式:
{
"error": {
"code": 400,
"message": "请求参数错误",
"status": "INVALID_ARGUMENT"
}
}
错误处理实现规范
WriteRelayError(w, err)— 写入 OpenAI 格式错误,用于/v1/chat/completions、/v1/embeddings等 OpenAI 格式端点WriteClaudeRelayError(w, err)— 写入 Claude 格式错误,用于/v1/messages端点- 平台级错误(余额不足、渠道不可用、频率限制)转换为供应商原生格式的错误类型,消息使用中文
- 上游供应商错误原样透传,不做二次包装
- 限流错误额外设置
X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset响应头
中间件配置差异
| 中间件 | 管理接口 | 代理接口 |
|---|---|---|
| AdminAuth / TenantAuth(JWT) | 使用 | 不使用 |
| ApiKeyAuth(Bearer Token) | 不使用 | 使用 |
| MiddlewareHandlerResponse(统一响应) | 使用 | 不使用 |
| ErrorHandler | 使用(支付回调) | 不使用 |
| MaintenanceMode(维护模式) | 使用(租户) | 使用 |
| ContentFilter(内容过滤) | 不使用 | 使用 |
| OperationLog(操作日志) | 使用(管理后台) | 不使用 |
| OpenPlatformAuth(HMAC-SHA256) | 仅开放平台 | 不使用 |
| RBAC(权限校验) | 使用 | 不使用 |
| Idempotency(幂等性) | 按需使用 | 不使用 |
| RequestID 注入 | 使用 | 使用 |