参考
HTTP API
/v1/* 与 /api/admin/* 路由的鉴权边界、请求方式和返回形态。
如果你已经在用 SDK,通常不需要手写 HTTP 请求。
这页更适合:
- 你在接别的运行时
- 你在调试 Base 的真实请求
- 你要确认某个路由到底返回什么
路由分组
产品侧路由
这些路由给 UserClient 或终端产品使用,统一要求 user_token:
| 路由 | 方法 | 用途 |
|---|---|---|
/v1/models | GET | 返回公开模型目录 |
/v1/services | GET | 返回已注册的 service 列表 |
/v1/invoke | POST | 通用 service 调用入口 |
/v1/text | POST | 文本 service |
/v1/stream | POST | 流式文本 service |
/v1/image | POST | 图像 service |
/v1/video | POST | 视频 service |
/v1/tts | POST | TTS service |
/v1/asr | POST | ASR service |
管理端路由
这些路由给 AdminClient 或可信环境使用,统一要求 admin_secret_key:
| 路由 | 方法 | 用途 |
|---|---|---|
/api/admin/products | GET | 返回 product 列表 |
/api/admin/products/create | POST | 创建 product |
/api/admin/products/pause | POST | 暂停 product |
/api/admin/products/activate | POST | 启用 product |
/api/admin/products/remove | POST | 删除 product |
/api/admin/tokens/apply | POST | 签发 user_token |
/api/admin/env | GET | 查看 Runtime env |
/api/admin/env/upsert | POST | 写入 Runtime env |
/api/admin/env/remove | POST | 删除某个 env 变量 |
/api/admin/env/import | POST | 批量导入 .env 文本 |
产品侧请求格式
认证头
产品侧请求统一使用:
Authorization: Bearer <user_token>
Content-Type: application/jsonGET /v1/models
[
{
"id": "gpt-5.4",
"name": "GPT-5.4",
"provider": "openai",
"description": "Primary text model",
"primary": true
}
]GET /v1/services
{
"items": ["text", "stream", "image"]
}POST /v1/text
请求:
{
"product_id": "prod_xxx",
"model": "gpt-5.4",
"prompt": "写一段欢迎语"
}返回:
{
"id": "msg_xxx",
"role": "assistant",
"parts": [
{
"type": "text",
"text": "欢迎使用 VisibleBase",
"state": "done"
}
]
}具体返回体由你的 service handler 决定。用 UserClient.text() 时,建议 handler 返回 AI SDK UIMessage。
POST /v1/invoke
请求:
{
"service": "rewrite",
"product_id": "prod_xxx",
"model": "gpt-5.4",
"prompt": "把这段话改得更专业"
}这和 POST /v1/text 的区别只是:service 名称由请求体显式提供。
POST /v1/stream
请求体和 text 类似:
{
"product_id": "prod_xxx",
"model": "gpt-5.4",
"prompt": "流式输出一段文案"
}但返回值不是普通 JSON,而是流式响应体。用 UserClient.stream() 时,Base 侧应该返回 AI SDK UIMessage stream response,client 会把它解析成 UIMessageChunk 流。
管理端请求格式
认证头
管理端请求统一使用:
Authorization: Bearer <admin_secret_key>
Content-Type: application/jsonPOST /api/admin/products/create
请求:
{
"name": "Chrome Extension"
}返回:
{
"product_id": "prod_xxx",
"name": "Chrome Extension",
"status": "active",
"created_at": "2026-04-23T00:00:00.000Z",
"updated_at": "2026-04-23T00:00:00.000Z"
}POST /api/admin/tokens/apply
请求:
{
"product_id": "prod_xxx",
"user_id": "user_123",
"metadata": {
"plan": "pro"
},
"ttl": "7d"
}返回:
{
"user_token": "ub_xxx",
"product_id": "prod_xxx",
"user_id": "user_123",
"expires_at": "2026-04-30T00:00:00.000Z"
}POST /api/admin/env/upsert
请求:
{
"key": "OPENAI_API_KEY",
"value": "sk-xxx"
}POST /api/admin/env/remove
请求:
{
"key": "OPENAI_API_KEY"
}POST /api/admin/env/import
请求:
{
"raw": "OPENAI_API_KEY=sk-xxx\nOPENAI_BASE_URL=https://api.openai.com/v1"
}常见状态码
Base 自己产生的错误统一返回 JSON:
{
"error": "Invalid user token"
}如果 service handler 直接返回 Response,Base 会原样透传这个 Response。如果 handler 抛错,Base 会先执行当前 service 和全局的 onError hook,然后把错误转成 HTTP 响应:带 statusCode 的错误使用该状态码,其他错误返回 500。
| 状态码 | 什么时候返回 |
|---|---|
200 | 请求成功,或 service handler 正常返回 JSON。 |
400 | /v1/invoke 请求体缺少 service。 |
401 | 产品侧请求缺少 user_token;token 过期、签名无效、audience 无效、payload 无效;token 对应的 product 已不存在;管理端请求缺少或传错 admin_secret_key。 |
403 | 请求体里的 product_id 和 token 内的 product 不一致;token 对应 product 已暂停;给已暂停 product 签发 token。 |
404 | HTTP 路由不存在;调用了未注册的 service;给不存在的 product 签发 token。 |
422 | service 最终没有 query.model;请求的 model 不存在或不是 active;当前 service 的 match() 没有任何 handler 命中。 |
500 | Base 必要配置缺失,例如 VISIBLEBASE_TOKEN_SIGNING_KEY 或 VISIBLEBASE_ADMIN_SECRET_KEY;service 已注册但没有 handler;handler、provider、数据库或 env 逻辑抛出了未显式指定 statusCode 的错误。 |
在自定义 handler 里,如果你想控制 HTTP 状态码,可以抛出带 statusCode 的错误:
import type { ErrorWithStatus } from "@visiblebase/base";
const error = new Error("quota exceeded") as ErrorWithStatus;
error.statusCode = 429;
throw error;