API Conventions
Shared conventions for Cosmos service APIs: base URLs, authentication, required headers, error shapes, and pagination styles.
Updated 2026-11-03
Verified 2026-11-03
Cosmos is a set of independent services, each with its own REST or WebSocket API. They share an authentication model and a few headers, but error and pagination shapes differ by service framework. This page describes what is common and where each service differs. The per-service API references link here instead of repeating these rules.
Base URLs
Every service serves its routes under /api/v1/ (health checks are unversioned). How you reach a service depends on the environment:
| Environment | URL pattern | Example |
|---|---|---|
| Local development | http://localhost:<port> (direct container port) | http://localhost:8101/api/v1/users/me/ |
| Per-service hosts | https://<service>-webserver.<domain> | https://user-webserver.<domain>/api/v1/users/me/ |
| Gateway deployments | https://<host>/cosmos/<service> | https://<host>/cosmos/user/api/v1/users/me/ |
In gateway deployments the gateway strips the /cosmos/<service> prefix before forwarding, so the service sees the same /api/v1/... path in every environment. Gateway path segments are user, configurator, adk, chat, observer, storage, ragflow, voice, and bridge; the knowledge-base API uses kb.
Local development ports:
| Port | Service |
|---|---|
| 8100 | Configurator |
| 8101 | User Service |
| 8102 | MCP Tools Server |
| 8103 | ADK |
| 8104 | Observer |
| 8106 | Voice |
| 8107 | Storage |
| 8108 | Chat |
| 8109 | Bridge |
| 8200 | RAGflow |
Authentication
All non-health endpoints require a JWT issued by the User Service, sent as a bearer token:
Authorization: Bearer YOUR_TOKEN
- User tokens come from
POST /api/v1/users/login/(plus the email-code step when MFA is required) or from the OAuth2 authorization-code flow. See Authentication API. - Service tokens are short-lived, audience-bound tokens that services obtain from
POST /oauth/token/with the OAuth2client_credentialsgrant. They carryactor_type: "service". When a service acts for an end user it also sends one subject header (see below). - Services validate tokens against the User Service JWKS endpoint (
/.well-known/jwks.json, RS256). - WebSocket endpoints accept the token in the
Authorizationheader. Browser clients that cannot set headers pass it as a WebSocket subprotocol where the service supports it (for example Chat acceptsSec-WebSocket-Protocol: cosmos.v1, cosmos-auth.YOUR_TOKEN). WebSocket authentication failures close the socket with code4401; authorization failures use4403.
A missing or invalid token returns 401. A token that is valid but lacks the required permission returns 403.
Required Headers
| Header | Required | Purpose |
|---|---|---|
Authorization | Yes (except health checks and public auth endpoints) | Bearer YOUR_TOKEN |
X-Org-Id | Yes for organization-scoped endpoints | Organization UUID that scopes the request, for example YOUR_ORG_ID. Services check that the caller belongs to this organization. |
X-Project-Id | Optional | Project UUID that narrows the request to a project. Services that are not project-aware ignore it. Where it is honoured: User Service project routes require it to match the project in the path; Storage uses it for activity attribution; Observer uses it to scope the activity feed; RAGflow uses it for project-scoped knowledge-base search; ADK and Configurator accept it for project-scoped authorization. |
X-On-Behalf-Of-User-Id | Service callers only | User ID a service token acts for. Some services also accept X-Subject-User-Id, X-Cosmos-Subject-User-Id, or X-Actor-User-Id; send exactly one. |
X-Token-Mode | Optional (User Service login and refresh) | body returns refresh tokens in the JSON body instead of the cosmos_refresh cookie. |
Content-Type | For request bodies | application/json, or multipart/form-data for uploads. |
When X-Org-Id is missing, services respond differently: Storage returns 400, Chat and Observer return 401, and User Service rejects organization-scoped and project requests. Health checks and the User Service login, refresh, and password-reset endpoints do not need it.
Errors
Error bodies follow the conventions of each service's framework. Check the status code first; the body shape varies.
| Service | Typical error body |
|---|---|
| User Service, Configurator (Django REST Framework) | {"detail": "..."}, or a field map such as {"email": ["This field is required."]} for validation errors. MFA and project endpoints add a machine-readable code: {"error": "invalid_code", "detail": "...", ...} or {"code": "duplicate", "detail": "..."}. |
| ADK, Observer, Chat, MCP (FastAPI) | {"detail": "..."}. Request validation errors return 422 with {"detail": [{"type": "...", "loc": [...], "msg": "..."}]}. Auth middleware errors use {"error": "..."} (Observer) or {"error": "unauthorized", "message": "..."} (Chat). |
| Storage | {"error": "BadRequest", "status": 400, "message": "..."}; validation errors use the same shape with status 422. |
| RAGflow | Validation errors return 422 with the FastAPI detail list; service errors return {"detail": "...", "code": "...", "context": {...}}. |
| Voice | {"status": "error", "code": "...", "message": "..."}. |
Common status codes:
| Status | Meaning |
|---|---|
400 | Invalid request, missing required header or field |
401 | Missing, invalid, or expired token |
403 | Authenticated but not permitted |
404 | Resource not found or not visible to the caller |
409 | Conflict (duplicate name, resource in use, inactive project) |
422 | Request body failed validation (FastAPI services) |
429 | Rate limited (for example MFA and password-reset throttles) |
503 | A dependency (authorization service, analytics backend) is unavailable |
Pagination
Services use one of three pagination styles.
Page-number pagination. Query with page (1-based) and page_size.
| Service | Default / max page_size | Response envelope |
|---|---|---|
| User Service (most lists) | 10 / 100 | {"count", "next", "previous", "results"} |
| Configurator | 20 / 100 | {"total_count", "current_page", "page_size", "total_pages", "next", "previous", "results"} |
| Observer (sessions, frontend logs) | 20 / 100 | Same envelope as Configurator. Observer session lists add summary and the time range. |
Cursor pagination. Follow the opaque cursor returned by the previous page.
| Service | Parameters | Response envelope |
|---|---|---|
| User Service projects and project members | limit (1–100, default 25), cursor | {"results", "next", "previous"}. Cursors are signed, bound to the query, and expire after 24 hours. |
| Storage item browse | page_size (default 20, max 100), next_cursor | {"results", "next_cursor", "page_size"} |
| Observer activity feed | limit (default 50), cursor; or page/page_size | Cursor page or numbered page |
Unpaginated lists. Some admin lists return everything when you pass mode=all (User Service permissions and roles). Other endpoints, such as the User Service project roles list, return {"results": [...]} without paging.