HTTP API
Auth, requests, and responses under the unified `/v1/*` route space.
All actions are exposed through the same shape:
POST /v1/{service}/{action}
GET /v1/{service}/{action}The bearer credential decides the request identity:
- no token:
guest user_token:user- administrator session token:
admin
Each action declares which identities it allows. The default is ["user"]; [] means guest access is allowed.
City Routes (common user-side routes)
| Route | Method | Purpose | Pathway |
|---|---|---|---|
/v1/ai/models | GET | Model catalog | — |
/v1/ai/stream | POST | Downcity Model Protocol stream transport | CityModel |
/v1/ai/image/create | POST | Create image generation job | SDK |
/v1/ai/image/result | POST | Poll image generation job | SDK |
/v1/ai/video | POST | Video generation | SDK |
/v1/ai/tts | POST | Text-to-speech | SDK |
/v1/ai/asr | POST | Speech recognition | SDK |
/v1/ai/chat/completions | POST | OpenAI-compatible endpoint | OpenAI |
/v1/accounts/login/start | POST | Create a login attempt; returns input, redirect, or done | — |
/v1/accounts/login/continue | POST | Submit an input login step | — |
/v1/accounts/login/result | GET | Read the login result and user_token | — |
/v1/accounts/me | GET | Read the current user and its verified Bureau | — |
/v1/accounts/oauth/callback | GET | Third-party OAuth callback entry | — |
/v1/services | GET | Registered service list | — |
/v1/{service}/{action} | POST | Generic action call | — |
/v1/accounts/oauth/callback is the fixed return URL for GitHub, Google, and other third-party OAuth providers. Product clients usually do not call it directly.
Admin Routes (same route space, admin credential required)
| Route | Method | Purpose |
|---|---|---|
/v1/bureaus/list | GET | List Bureaus |
/v1/bureaus/create | POST | Create a Bureau with required server_url |
/v1/bureaus/pause | POST | Pause a Bureau |
/v1/bureaus/activate | POST | Activate a Bureau |
/v1/bureaus/archive | POST | Archive a Bureau |
/v1/bureaus/server/update | POST | Update the Bureau's single Server entrypoint |
/v1/bureaus/current | GET | Resolve the current Bureau from a User Token |
/v1/accounts/tokens/issue | POST | Issue user_token |
/v1/env/list | GET | View runtime env |
/v1/env/upsert | POST | Write env variable |
/v1/env/remove | POST | Delete env variable |
/v1/env/import | POST | Bulk import .env |
Auth Header
Authorization: Bearer <user_token>
Content-Type: application/jsonGET /v1/ai/models
The same route returns different visibility by identity:
- with
user_token: only currently callable models - with an administrator session token: the full code-registered model list plus
env_requirements
{ "items": [
{ "id": "deepseek-v4-flash", "name": "DeepSeek V4 Flash",
"description": "...", "modalities": ["text","stream"],
"tags": ["deepseek"],
"price": ["Input: 1 credit / 1K tokens", "Output: 3 credits / 1K tokens"],
"meta": {},
"reasoning": {
"efforts": [
{ "id": "low", "name": "Low" },
{ "id": "high", "name": "High" }
],
"default_effort": "low"
} }
]}{ "items": [
{ "id": "deepseek-v4-flash", "name": "DeepSeek V4 Flash",
"description": "", "modalities": ["text","stream","openai"],
"tags": ["deepseek"],
"price": ["Input: 1 credit / 1K tokens", "Output: 3 credits / 1K tokens"],
"meta": {},
"env_requirements": [
{ "key": "DEEPSEEK_API_KEY", "description": "deepseek API Key", "required": true }
] }
]}Federation resolves both the user and Bureau identity from the bearer user_token. The request body
does not participate in identity resolution.
GET /v1/services
{
"items": [
{ "id": "ai", "name": "AI", "env": [] },
{ "id": "accounts", "name": "Accounts", "env": [] }
]
}env exposes the runtime env requirements declared by the service so admin or debugging surfaces can render dependencies.
POST /v1/ai/stream
This versioned Downcity Model Protocol transport accepts
{ protocol_version: 1, model_id, call }, where call is a ModelCall containing
messages, tools, reasoning, and generation options. SSE returns
{ protocol_version: 1, event: ModelStreamEvent }. Product code should use the
CityModel returned by the catalog or call city.ai.stream({ model, call }).
Both paths consume the same standard event stream.
When supplied, call.reasoning.effort must match the final model catalog's
reasoning.efforts. AIService validates it again after fallback selects the
execution model.
POST /v1/ai/chat/completions
OpenAI-compatible endpoint. Accepts standard { model, messages, stream } format.
Non-streaming returns OpenAI chat.completion JSON. Streaming returns OpenAI SSE.
Fully compatible with OpenAI SDK:
const openai = new OpenAI({
baseURL: "http://127.0.0.1:43127/v1/ai",
apiKey: "ub_xxx",
});