HTTP API
统一 `/v1/*` 路由下的鉴权边界、请求方式和返回形态。
如果你已经在用 SDK,通常不需要手写 HTTP 请求。
路由规则
所有 Action 自动映射为 HTTP 路由:
动作 URL
──── ───
普通 action POST /v1/{service}/{action}
GET action GET /v1/{service}/{action}
Admin action POST /v1/{service}/{action}
Admin GET GET /v1/{service}/{action}产品侧路由
| 路由 | 方法 | 用途 |
|---|---|---|
/v1/ai/text | POST | 文本生成(SDK 通路) |
/v1/ai/stream | POST | CityModel LanguageModelV3 模型流 |
/v1/ai/image/create | POST | 创建图片生成任务 |
/v1/ai/image/result | POST | 查询图片生成任务 |
/v1/ai/video | POST | 视频生成 |
/v1/ai/chat/completions | POST | OpenAI 兼容端点 |
/v1/ai/models | GET | 按身份返回模型目录 |
/v1/accounts/login/start | POST | 创建登录流程;返回 input、redirect 或 done |
/v1/accounts/login/continue | POST | 提交 input 登录步骤 |
/v1/accounts/login/result | GET | 读取登录结果和 user_token |
/v1/accounts/me | GET | 读取当前用户及其已验证的 Bureau |
/v1/accounts/oauth/callback | GET | 第三方 OAuth 回调入口 |
/v1/{service}/{action} | POST | 通用 Action 调用 |
/v1/services | GET | Service 列表 |
/v1/accounts/oauth/callback 是给 GitHub / Google 这类第三方 OAuth 平台回跳用的固定地址。产品前端通常不直接调用它。
管理端常用路由
| 路由 | 方法 | 用途 |
|---|---|---|
/v1/bureaus/list | GET | Bureau 列表 |
/v1/bureaus/create | POST | 创建 Bureau,必须提供 server_url |
/v1/bureaus/pause | POST | 暂停 Bureau |
/v1/bureaus/activate | POST | 启用 Bureau |
/v1/bureaus/archive | POST | 归档 Bureau |
/v1/bureaus/server/update | POST | 更新 Bureau 唯一 Server 的服务入口 |
/v1/bureaus/current | GET | 按 User Token 解析当前 Bureau |
/v1/accounts/tokens/issue | POST | 签发 user_token |
/v1/env/list | GET | 环境变量列表 |
/v1/env/upsert | POST | 写入环境变量 |
/v1/env/remove | POST | 删除环境变量 |
/v1/env/import | POST | 批量导入 .env |
同一条 /v1/{service}/{action} 路由会根据 bearer 凭证决定身份: |
- 不带 token:
guest - 带
user_token:user - 带管理员会话 Token:
admin
Action 自己声明允许哪些身份访问。默认是 ["user"];传 [] 表示免登录。
产品侧请求格式
认证头
Authorization: Bearer <user_token>
Content-Type: application/json同一个 /v1/ai/models:
user_token访问时,只返回当前可调用模型- 管理员会话 Token 访问时,返回全部代码注册模型,并附带
env_requirements
GET /v1/ai/models
user_token 示例:
{
"items": [
{
"id": "deepseek-v4-flash",
"name": "DeepSeek V4 Flash",
"description": "DeepSeek text model",
"modalities": ["text", "stream"],
"tags": ["deepseek", "text"],
"price": ["输入:1 credit / 1K tokens", "输出:3 credits / 1K tokens"],
"meta": {},
"reasoning": {
"efforts": [
{ "id": "low", "name": "低" },
{ "id": "high", "name": "高" }
],
"default_effort": "low"
}
}
]
}管理员会话 Token 示例:
{
"items": [
{
"id": "deepseek-v4-flash",
"name": "DeepSeek V4 Flash",
"description": "",
"modalities": ["text", "stream", "openai"],
"tags": ["deepseek", "text"],
"price": ["输入:1 credit / 1K tokens", "输出:3 credits / 1K tokens"],
"meta": {},
"env_requirements": [
{
"key": "DEEPSEEK_API_KEY",
"description": "deepseek API Key",
"required": true
}
]
}
]
}POST /v1/ai/text
请求(SDK 通路):
{
"model": "deepseek-v4-flash",
"prompt": "写一段欢迎语",
"reasoning_effort": "high"
}reasoning_effort 可选,但传入时必须匹配模型目录中的 reasoning.efforts[].id。请求经过模型 fallback 时,AIService 会按照最终执行模型重新校验该档位。
返回:
{
"id": "msg_xxx",
"role": "assistant",
"parts": [
{ "type": "text", "text": "欢迎使用 Downcity" }
]
}POST /v1/ai/stream
这是 CityModel 使用的版本化 LanguageModelV3 transport。请求包含协议版本、模型
ID 和标准模型调用参数:
{
"protocol": "downcity-language-model-v1",
"model_id": "deepseek-v4-flash",
"call": {
"prompt": [
{ "role": "user", "content": [{ "type": "text", "text": "你好" }] }
]
},
"reasoning_effort": "high"
}Federation 通过 SSE 返回版本化 LanguageModelV3StreamPart。产品代码不应手写该
transport 请求:把模型目录返回的 CityModel 交给 Agent / AI SDK,或者调用
city.ai.stream()。后者在客户端将同一模型流转换成 UIMessageChunk。
AI 请求的用户和 Bureau 身份完全由 bearer user_token 解析,请求体不参与身份判断。
POST /v1/ai/chat/completions
OpenAI 兼容端点。接收标准 OpenAI chat/completions 格式:
{
"model": "deepseek-v4-flash",
"messages": [{ "role": "user", "content": "写一段欢迎语" }],
"stream": true
}返回 SSE 流:
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"欢迎"},"finish_reason":null}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{...}}
data: [DONE]直接用 OpenAI SDK:
const openai = new OpenAI({
baseURL: "http://127.0.0.1:43127/v1/ai",
apiKey: "ub_xxx",
});
await openai.chat.completions.create({
model: "deepseek-v4-flash",
messages: [{ role: "user", content: "你好" }],
stream: true,
});GET /v1/services
{
"items": [
{ "id": "ai", "name": "AI", "env": [] },
{ "id": "accounts", "name": "Accounts", "env": [] }
]
}env 用于暴露该 service 声明的运行时环境变量需求,便于管理端或调试界面展示依赖项。
POST /v1/{service}/{action}
{ "text": "你好" }管理端请求格式
认证头
Authorization: Bearer <admin_session_token>
Content-Type: application/jsonPOST /v1/bureaus/create
{ "name": "Chrome Extension", "server_url": "https://bureau.example.com" }{ "bureau_id": "product_id", "name": "Chrome Extension", "server": { "bureau_id": "product_id", "server_url": "https://bureau.example.com", ... }, "state": "active", ... }POST /v1/accounts/tokens/issue
{
"bureau_id": "product_id",
"user_id": "user_123",
"metadata": { "plan": "pro" },
"ttl": "7d"
}{ "user_token": "ub_xxx", "bureau_id": "product_id", "user_id": "user_123", ... }POST /v1/env/upsert
{ "key": "DEEPSEEK_API_KEY", "value": "sk-xxx" }常见状态码
| 状态码 | 什么时候返回 |
|---|---|
200 | 请求成功 |
401 | token 缺失、过期、签名无效 |
403 | Token 所属 Bureau 已暂停或没有调用权限 |
404 | 路由不存在、service 未注册 |
422 | model 不存在、action 未命中 |
500 | action 逻辑抛出未指定 statusCode 的错误 |