Reference

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)

RouteMethodPurposePathway
/v1/ai/modelsGETModel catalog
/v1/ai/textPOSTText generationSDK
/v1/ai/streamPOSTCityModel LanguageModelV3 stream transportCityModel
/v1/ai/image/createPOSTCreate image generation jobSDK
/v1/ai/image/resultPOSTPoll image generation jobSDK
/v1/ai/videoPOSTVideo generationSDK
/v1/ai/ttsPOSTText-to-speechSDK
/v1/ai/asrPOSTSpeech recognitionSDK
/v1/ai/chat/completionsPOSTOpenAI-compatible endpointOpenAI
/v1/accounts/login/startPOSTCreate a login attempt; returns input, redirect, or done
/v1/accounts/login/continuePOSTSubmit an input login step
/v1/accounts/login/resultGETRead the login result and user_token
/v1/accounts/meGETRead the current user and its verified Bureau
/v1/accounts/oauth/callbackGETThird-party OAuth callback entry
/v1/servicesGETRegistered service list
/v1/{service}/{action}POSTGeneric 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)

RouteMethodPurpose
/v1/bureaus/listGETList Bureaus
/v1/bureaus/createPOSTCreate a Bureau with required server_url
/v1/bureaus/pausePOSTPause a Bureau
/v1/bureaus/activatePOSTActivate a Bureau
/v1/bureaus/archivePOSTArchive a Bureau
/v1/bureaus/server/updatePOSTUpdate the Bureau's single Server entrypoint
/v1/bureaus/currentGETResolve the current Bureau from a User Token
/v1/accounts/tokens/issuePOSTIssue user_token
/v1/env/listGETView runtime env
/v1/env/upsertPOSTWrite env variable
/v1/env/removePOSTDelete env variable
/v1/env/importPOSTBulk import .env

Auth Header

Authorization: Bearer <user_token>
Content-Type: application/json

GET /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 }
    ] }
]}

POST /v1/ai/text

Request:

{ "model": "deepseek-v4-flash", "prompt": "Hello", "reasoning_effort": "high" }

reasoning_effort is optional, but when present it must match an ID from the model catalog's reasoning.efforts. If model fallback changes the execution model, AIService validates the level against that final model.

Response:

{ "id": "msg_xxx", "role": "assistant", "parts": [{ "type": "text", "text": "Hi!" }] }

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 LanguageModelV3 transport is internal to CityModel. It carries standard model prompts, function tools, reasoning, usage, and finish reasons as SSE events. Product code should use the CityModel returned by the model catalog instead of constructing transport requests manually. city.ai.stream() uses the same transport and converts model parts into UIMessageChunk objects in the SDK.

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",
});