openapi: 3.0.3 info: title: Chat Switchboard API description: | Multi-provider AI chat platform with team workspaces, workflow automation, and extensibility via Starlark packages. **Authentication:** Most endpoints require a Bearer JWT token obtained via `POST /api/v1/auth/login`. Include it as `Authorization: Bearer `. **WebSocket:** Real-time events are delivered over WebSocket at `/ws`. Obtain a ticket via `POST /api/v1/ws/ticket` and connect with `?ticket=`. version: "${VERSION}" contact: name: Chat Switchboard servers: - url: / description: Current instance tags: - name: Auth description: Authentication and session management - name: Channels description: Chat channel CRUD and messaging - name: Completions description: AI completion requests (streaming and non-streaming) - name: Health description: System health and readiness probes - name: Admin description: Platform administration (requires admin role) - name: Usage description: Token usage and cost tracking - name: WebSocket description: Real-time event delivery paths: # ── Auth ─────────────────────────────────── /api/v1/auth/register: post: tags: [Auth] summary: Register a new user requestBody: required: true content: application/json: schema: type: object required: [username, password] properties: username: type: string minLength: 3 password: type: string minLength: 8 email: type: string format: email display_name: type: string responses: "201": description: User created content: application/json: schema: $ref: "#/components/schemas/AuthResponse" "400": $ref: "#/components/responses/BadRequest" "409": description: Username already taken /api/v1/auth/login: post: tags: [Auth] summary: Authenticate and obtain JWT tokens requestBody: required: true content: application/json: schema: type: object required: [username, password] properties: username: type: string password: type: string responses: "200": description: Login successful content: application/json: schema: $ref: "#/components/schemas/AuthResponse" "401": description: Invalid credentials "429": description: Rate limited /api/v1/auth/refresh: post: tags: [Auth] summary: Refresh an expired access token requestBody: required: true content: application/json: schema: type: object required: [refresh_token] properties: refresh_token: type: string responses: "200": description: New token pair content: application/json: schema: $ref: "#/components/schemas/AuthResponse" "401": description: Invalid or expired refresh token /api/v1/auth/logout: post: tags: [Auth] summary: Invalidate the current session security: - bearerAuth: [] responses: "200": description: Logged out # ── Channels ─────────────────────────────── /api/v1/channels: get: tags: [Channels] summary: List channels accessible to the current user security: - bearerAuth: [] parameters: - name: type in: query schema: type: string enum: [direct, group, workflow] - name: page in: query schema: type: integer default: 1 - name: per_page in: query schema: type: integer default: 50 responses: "200": description: Channel list content: application/json: schema: type: object properties: channels: type: array items: $ref: "#/components/schemas/Channel" total: type: integer post: tags: [Channels] summary: Create a new channel security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: title: type: string type: type: string enum: [direct, group] default: direct system_prompt: type: string responses: "201": description: Channel created content: application/json: schema: $ref: "#/components/schemas/Channel" /api/v1/channels/{id}: get: tags: [Channels] summary: Get channel details security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/ChannelID" responses: "200": description: Channel details content: application/json: schema: $ref: "#/components/schemas/Channel" "404": $ref: "#/components/responses/NotFound" put: tags: [Channels] summary: Update channel settings security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/ChannelID" requestBody: required: true content: application/json: schema: type: object properties: title: type: string system_prompt: type: string ai_mode: type: string enum: [auto, off, mention_only] responses: "200": description: Updated delete: tags: [Channels] summary: Archive a channel security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/ChannelID" responses: "200": description: Archived # ── Completions ──────────────────────────── /api/v1/chat/completions: post: tags: [Completions] summary: Send a message and get an AI completion description: | Streams SSE events by default. Set `stream: false` for a single JSON response. Supports tool calling, @mentions, multi-model routing, and workflow integration. security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [content, channel_id] properties: channel_id: type: string format: uuid content: type: string model: type: string description: Override the default model persona_id: type: string format: uuid provider_config_id: type: string format: uuid max_tokens: type: integer temperature: type: number minimum: 0 maximum: 2 top_p: type: number minimum: 0 maximum: 1 stream: type: boolean default: true file_ids: type: array items: type: string format: uuid disabled_tools: type: array items: type: string responses: "200": description: | **Streaming:** SSE events (`data: {"content":"..."}`, `data: [DONE]`). **Non-streaming:** OpenAI-compatible JSON response. content: text/event-stream: schema: type: string application/json: schema: type: object properties: model: type: string choices: type: array items: type: object properties: message: type: object properties: role: type: string content: type: string finish_reason: type: string usage: type: object properties: prompt_tokens: type: integer completion_tokens: type: integer total_tokens: type: integer "400": $ref: "#/components/responses/BadRequest" "429": description: Token budget exceeded # ── Health ───────────────────────────────── /health: get: tags: [Health] summary: Basic health check responses: "200": description: System status content: application/json: schema: type: object properties: status: type: string example: ok version: type: string database: type: boolean schema_version: type: integer /healthz/live: get: tags: [Health] summary: Kubernetes liveness probe responses: "200": description: Process alive /healthz/ready: get: tags: [Health] summary: Kubernetes readiness probe description: Returns 503 if the database is unreachable (2s timeout). responses: "200": description: Ready to serve traffic "503": description: Database unavailable /metrics: get: tags: [Health] summary: Prometheus metrics endpoint description: | Returns all `switchboard_*` metrics in Prometheus text exposition format. Includes HTTP request latency, WebSocket connections, completion tokens, DB pool stats, and provider health gauges. responses: "200": description: Prometheus text format content: text/plain: schema: type: string # ── WebSocket ────────────────────────────── /api/v1/ws/ticket: post: tags: [WebSocket] summary: Obtain a WebSocket connection ticket description: | Returns a single-use ticket (30s TTL) for authenticating the WebSocket upgrade at `/ws?ticket=`. Cross-pod safe (v0.32.0). security: - bearerAuth: [] responses: "200": description: Ticket issued content: application/json: schema: type: object properties: ticket: type: string # ── Admin: Stats ─────────────────────────── /api/v1/admin/stats: get: tags: [Admin] summary: Platform statistics security: - bearerAuth: [] responses: "200": description: Aggregate counts content: application/json: schema: type: object properties: users: type: integer channels: type: integer messages: type: integer # ── Admin: Provider Health ───────────────── /api/v1/admin/providers/health: get: tags: [Admin] summary: Current health status for all providers security: - bearerAuth: [] responses: "200": description: Provider health summaries content: application/json: schema: type: object properties: providers: type: array items: $ref: "#/components/schemas/ProviderHealth" # ── Admin: Usage ─────────────────────────── /api/v1/admin/usage: get: tags: [Admin, Usage] summary: Aggregated token usage security: - bearerAuth: [] parameters: - name: since in: query schema: type: string format: date-time - name: until in: query schema: type: string format: date-time - name: period in: query schema: type: string enum: [7d, 30d, 90d] - name: group_by in: query schema: type: string enum: [model, user, provider, day] responses: "200": description: Usage data # ── Admin: Dashboard ─────────────────────── /api/v1/admin/dashboard: get: tags: [Admin] summary: Real-time observability dashboard data description: | Aggregates provider health, 24h usage, DB pool stats, WebSocket count, recent errors, and uptime into a single response. Designed for the built-in admin dashboard (v0.33.0). security: - bearerAuth: [] responses: "200": description: Dashboard snapshot content: application/json: schema: type: object properties: providers: type: array items: $ref: "#/components/schemas/ProviderHealth" usage_24h: type: object db_pool: type: object properties: open_connections: type: integer in_use: type: integer idle: type: integer ws_connections: type: integer uptime_seconds: type: number components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT parameters: ChannelID: name: id in: path required: true schema: type: string format: uuid responses: BadRequest: description: Invalid request content: application/json: schema: type: object properties: error: type: string NotFound: description: Resource not found content: application/json: schema: type: object properties: error: type: string schemas: AuthResponse: type: object properties: token: type: string refresh_token: type: string user: type: object properties: id: type: string format: uuid username: type: string role: type: string enum: [admin, user] Channel: type: object properties: id: type: string format: uuid title: type: string type: type: string enum: [direct, group, workflow] user_id: type: string format: uuid team_id: type: string format: uuid ai_mode: type: string enum: [auto, off, mention_only] created_at: type: string format: date-time updated_at: type: string format: date-time ProviderHealth: type: object properties: provider_config_id: type: string format: uuid status: type: string enum: [healthy, degraded, down, unknown] request_count: type: integer error_count: type: integer error_rate: type: number avg_latency_ms: type: number max_latency_ms: type: integer