Back to docs
Guide 04

API Reference

REST API of the Express server (port 3000, prefix /api), with an interactive Swagger UI and an OpenAPI spec served by the server itself, documented here by domain with its authentication mechanisms, rate limits, and response conventions.

7 min read

REST API of the Express server (port 3000, prefix /api), with an interactive Swagger UI and an OpenAPI spec served by the server itself, documented here by domain with its authentication mechanisms, rate limits, and response conventions.

Authentication

MethodHeaderUsage
JWTAuthorization: Bearer <token>Internal users (frontend, Tauri)
API keyX-Api-Key: sk-...Widget embed, programmatic integrations
Collector secretX-Collector-SecretServer↔collector (constant-time comparison)
Query token?token=OCR image access

Middlewares (packages/server/src/middleware/): auth.ts, rbac.ts, license.ts, rateLimit.ts, widgetCors.ts.

Rate limit

LimiterLimit (prod/dev)Scope
general200 / 2000 req/minIP
auth10 / 100 req/minIP
probe10 / 100 req/minIP
widget chat30 / 200 req/min (per-widget override)widgetId
widget daily5 / 50 messages per daywidgetId + IP
widget session50 / 500 creations per dayIP
widget lead3 / 30 per hourIP

There is no dedicated chat rate limiter: the ReAct agent enforces its own limits internally (per-user concurrency, token budgets, wallclock timeouts - agentBudgetService.ts); the global 200/min limiter remains the safety net. Requests carrying an X-Widget-Id header skip the global limiter (the widget service throttles them upstream); widgets use rateLimitPerMinute / sessionLimitPerDay as per-widget overrides.

Response conventions

  • Success: JSON entity or { ok: true }.
  • Error: { error: string } (+ details for Zod validation errors).
  • License gating: 402 { error, feature, tier, limit?, current? }.
  • RBAC: 401 (no auth), 403 (insufficient permissions).
  • SSE: event: <type>\ndata: <json>\n\n.

Auth - /api/auth (routes/auth.ts)

MethodPathAuthRBACNotes
POST/auth/registerpublic-Only if ALLOW_REGISTRATION=true; body registerSchema
POST/auth/admin-registerJWTrequireAdminbody adminRegisterSchema
POST/auth/loginpublic-body loginSchema (safeParse → 400 when invalid) → { user, token }
GET/auth/meJWT-Current profile
GET/auth/usersJWTrequireAdminUser list
POST/auth/change-passwordJWT-changePasswordSchema
POST/auth/set-initial-passwordJWT-First login (mustChangePassword)
POST/auth/admin-reset-passwordJWTrequireAdminReset a user's password

Users - /api/users (routes/users.ts, authMiddleware)

MethodPathRBACNotes
GET/usersrequireAdminPaginated list
GET/users/:idself/admin
PUT/PATCH/users/:idself/adminupdateUserSchema
DELETE/users/:idrequireAdmin
POST/DELETE/users/:id/avatarJWTAvatar upload/removal (multipart)

Roles - /api/roles (routes/roles.ts, authMiddleware)

MethodPathRBACNotes
GET/roles/me/menu-sectionsJWTVisible sidebar sections
GET/rolesrequireAdminRole list
GET/roles/:roleIdrequireAdminDetail (UUID)
POST/rolesrequireAdminCreate role (createRoleSchema, isDefault=false)
PUT/roles/:roleIdrequireAdminUpdate (atomic permission replace)
PUT/roles/:roleId/menu-sectionsrequireAdminMenu sections
DELETE/roles/:roleIdrequireAdmin
POST/roles/assignrequireAdminAssign a role to a user
POST/roles/revokerequireAdminRevoke a role

Projects - /api/projects (routes/projects.ts, authMiddleware)

MethodPathRBACLicenseNotes
GET/projectsJWT-Paginated list
POST/projectsproject:createmax_projectsCreation
GET/projects/:projectIdrequireProjectAccess-
GET/projects/:projectId/usagerequireProjectAccess-Usage statistics
GET/projects/:projectId/exportrequireProjectAccess-Archive stream
PUT/projects/:projectIdrequireProjectAccess-
DELETE/projects/:projectIdrequireProjectAccess-Soft delete
POST/DELETE/projects/:projectId/accessrequireProjectAccess-ProjectAccess management

Workspaces - /api/workspaces (routes/workspaces.ts, authMiddleware)

MethodPathRBACLicenseNotes
GET/workspacesJWT-List
POST/workspacesworkspace:createmax_workspacesCreation
GET/PUT/DELETE/workspaces/:workspaceIdrequireWorkspaceAccess-Soft delete
PUT/workspaces/:workspaceId/restorerequireWorkspaceAccess-Restore soft-deleted
POST/workspaces/:workspaceId/accessrequireWorkspaceAccess-WorkspaceAccess
GET/POST/PUT/DELETE/workspaces/:workspaceId/folders[/:folderId]requireWorkspaceAccess-Chat folders
PUT/workspaces/:workspaceId/folders/:folderId/restorerequireWorkspaceAccess-

Chat - mounted under /api/workspaces (routes/chat*.ts, authMiddleware)

MethodPathRBACNotes
POST/workspaces/:id/chatrequireWorkspaceAccessNon-streaming → { chat, message }
POST/workspaces/:id/chat/streamrequireWorkspaceAccessSSE
GET/workspaces/:id/chatsrequireWorkspaceAccessPaginated list (chatList.ts)
GET/workspaces/:id/chats/:chatId/messagesrequireWorkspaceAccessPaginated messages
PUT/workspaces/:id/chats/:chatIdrequireWorkspaceAccessRename (chatCrud.ts)
PATCH/workspaces/:id/chats/:chatId/modelrequireWorkspaceAccessPer-chat model { providerId?, model? }
PATCH/workspaces/:id/chats/:chatId/folderrequireWorkspaceAccessMove to folder
DELETE/workspaces/:id/chats/:chatIdrequireWorkspaceAccess
PUT/workspaces/:id/chats/:chatId/moverequireWorkspaceAccessReorder
POST/DELETE/workspaces/:id/chats/:chatId/pinrequireWorkspaceAccessPin chat
DELETE/PUT/workspaces/:id/chats/:chatId/messages/:messageIdrequireWorkspaceAccessDelete/edit message
GET/workspaces/:id/agent-configrequireWorkspaceAccessWorkspace agent config (chatAgentConfig.ts)
PUT/workspaces/:id/agent-configrequireWorkspaceAccess
GET/workspaces/:id/chats/exportrequireWorkspaceAccessExport (json/md/pdf) (chatExport.ts)
GET/workspaces/:id/chats/:chatId/exportrequireWorkspaceAccess
POST/workspaces/:id/chats/import/previewrequireWorkspaceAccessImport preview (chatImport.ts)
POST/workspaces/:id/chats/import/confirmrequireWorkspaceAccessConfirm import
GET/workspaces/:id/chats/:chatId/tokensrequireWorkspaceAccessTokens used (chatTokens.ts)
GET/workspaces/:id/tokens/todayrequireWorkspaceAccess

SSE - /workspaces/:id/chat/stream

Events: token, status, citations ({ sources }), done ({ chatId, messageId, modelUsed, providerUsed, mcpSources }), error ({ error }), plus plan and wiki_edit.

Connectors (Enterprise) - /api/connectors (routes/connectors.ts, connectorOAuthCallback.ts) - F-CONN-2

Gating: authMiddleware → tenantContextMiddleware → requireAdmin → requireFeature("connectors_enabled") (Community: fail-closed, F-CONN-1); per-route connector:manage/connector:view. The platform webhooks run on a SEPARATE PUBLIC router (connectorsWebhookRouter, mounted on the same prefix - NO RBAC, per-platform signature/secret) and the OAuth callback on connectorOAuthCallback.ts.

MethodPathPermissionNotes
POST/connectorsconnector:manageCreate the connector (name/archive binding/welcome-fallback/fallback locale/limits)
GET/connectorsconnector:viewList
GET/connectors/:idconnector:viewDetail
PUT/connectors/:idconnector:manageEDIT (v0.28.1, F-CONN-2): name/binding/messages/limits editable - platform/token immutable; emits the chat_connector.updated audit event
DELETE/connectors/:idconnector:manageDelete
GET/connectors/oauth/providersconnector:manageAvailable OAuth providers

See 13 - Connectors.

Documents & Uploads (routes/documents.ts, routes/uploads.ts)

MethodPathRBACNotes
GET/documentsJWTList
GET/documents/:idJWTDetail
GET/documents/:id/textJWTExtracted text
POST/documents/uploaddocument:writeMultipart upload
PUT/documents/:id/status(pre-middleware)Collector callback
DELETE/documents/:iddocument:deleteSoft delete
POST/uploadsdocument:writeDraft staging (uploads.ts)
POST/uploads/:id/assigndocument:writeAssign draft to a workspace
GET/uploads/pendingdocument:writePending drafts
DELETE/PATCH/uploads/:iddocument:write

API Keys - /api/api-keys (routes/apiKeys.ts, authMiddleware)

GET lists your own keys, POST creates a new one (the raw sk-... key is shown once only), DELETE /:keyId revokes.

Since v0.20.1 API keys are HMAC-SHA256: the sk- key is no longer bcrypt-hashed but hashed with a dedicated HMAC-SHA256 digest (API_KEY_HMAC_SECRET, a dedicated env var decoupled from JWT/encryption key rotation) and verification is an indexed O(1) lookup on api_keys.key_hash (Postgres unique index), not a bcrypt-loop comparison. Breaking change in v0.20.1: operators must re-issue widget/collector keys (see docs/API_KEY_MIGRATION.md). Since v0.22.0 secret comparisons (X-Api-Key cache-bust, X-Collector-Secret) are timing-safe (crypto.timingSafeEqual with a length guard). A missing/invalid key → 401; a server-side HMAC misconfiguration → 500 (fail-loud).

Agent Skills - /api/agent + /api/skills (routes/skills.ts, authMiddleware)

GET /api/agent/skills → builtin skills (rag_search, workspace_memory, document_temp_process).

Custom skills (v0.28.1, F-SKILL-1): CRUD GET/POST/PUT/DELETE /api/skills[...] with the skill:read/skill:create/skill:write/skill:delete permissions; create is gated by the max_skills license limit (Community 3, Enterprise Infinity). Scopes personal/global/workspace with server-side arbitration. POST /api/skills/:id/test → compiled-prompt preview (no LLM call, no DLP masking). See 15 - Custom Skills.

MCP Connections - /api/mcp-connections (routes/mcp.ts, authMiddleware + requireAdmin)

GET list, GET /statuses (live runtime), POST create, PUT /:id (auto-disconnect/reconnect when enabled), DELETE /:id, POST /:id/toggle, POST /:id/test (10s timeout, toolCount).

MCP Pins - /api/chats/:chatId/pins (routes/mcpPins.ts)

GET, POST (mcpPinCreateSchema), DELETE /:pinId.

MCP Server inbound (for IDEs) - agent/mcpServer.ts

GET /api/mcp/sse (SSE transport), POST /api/mcp/message (JSON-RPC).

Marketplace - /api/mcp-marketplace (routes/marketplace.ts, authMiddleware + requireAdmin)

GET list (query ?search, ?category, ?workspaceId for isInstalled), GET /:entryId, POST create entry, POST /:entryId/install, POST /:entryId/uninstall. See 07 - MCP Marketplace.

Providers / Models - /api/providers (routes/providers.ts, authMiddleware)

GET /models/available (frontend selector), GET list, GET/:id, POST create, PUT/:id, DELETE/:id, PUT /:id/set-default, GET /:id/models, POST /:id/models/refresh (discovery), POST /:providerId/models/pull, PUT/DELETE /:providerId/models/:modelId, PUT /:providerId/models/:modelId/set-default.

Provider Presets - /api/provider-presets (routes/providerPresets.ts)

GET list, GET /:presetId, POST /:presetId/install.

Widget (admin) - /api/widgets (routes/widgets.ts, authMiddleware + requireAdmin)

GET list, POST (license widget_enabled + max_widgets), GET/PUT/DELETE /:id, PUT /:id/workspaces (whitelist), GET /:id/workspaces, GET /:id/leads (paginated), GET /:id/leads/export (CSV, license lead_export), GET /:id/leads/:leadId. Analytics: GET /analytics/daily, /analytics/topics, /analytics/summary.

Internal Widget (embed) - /api/internal/widget (routes/internalWidget.ts, apiKeyMiddleware + widgetCors)

Authentication via API key (X-Api-Key). POST /search (RAG, IDOR-safe via widgetId), POST /lead, GET /:id/config, GET /session/:token, POST /session, PATCH /session/:token/increment, PATCH /session/:token/chat/archive. See 06 - Widget Integration.

Backup (routes/backups.ts, backupDestinations.ts, backupJobs.ts, restore.ts)

GroupPathPermissionsLicense
Logs/api/system/backupsbackup:log:read-
Destinations/api/backup-destinationsbackup:destination:read/writemax_backup_destinations
Jobs/api/backup-jobsbackup:job:read/write-
Restore/api/backups, /api/backups/restore/:logId[/dry-run]backup:log:read / backup:restore:write-

POST /backup-jobs/:id/run (manual trigger), POST /backup-destinations/:id/test.

Webhooks - /api/webhooks (routes/webhooks.ts, authMiddleware + requireAdmin + requireFeature("webhooks"))

CRUD + POST /:id/test. HMAC-SHA256, exponential backoff retry (5 attempts), auto-disable after 5 failures.

Push - /api/system/push (routes/push.ts)

GET /vapid-key (public key), POST/DELETE /subscribe (license push_notifications), POST /test (admin).

License - /api/license (routes/license.ts)

GET /license/info (public) → { license, features }.

The instance-license slot (v0.28.1, F-LIC-1): GET /api/license/instance (Admin, metadata-only), PUT /api/license/instance ({ licenseKey } - paste + verify + persist + apply WITHOUT a restart; rejects are 400 { error, reason } with the closed reason invalid/expired/plugin_bound/community_tier), DELETE /api/license/instance (clears the paste - the instance reverts to the next-boot state). See 08 - Administration.

SSO - /api/sso (routes/sso.ts, authMiddleware + requireAdmin + requireFeature("sso_enabled"))

GET /config, PUT /config, POST /test.

Templates - /api/templates (routes/templates.ts, authMiddleware)

GET list, GET /:id, POST create, PUT/DELETE /:id (requireAdmin). {{var}} interpolation.

Settings - /api/system/settings (routes/settings.ts, authMiddleware + requireAdmin)

GET /embedding-config, GET /vector-db-config, GET settings, PUT settings ({ updated, rejected }), POST/DELETE /branding/icon (license white_label). See 03 - Configuration.

System - /api/system (routes/system.ts)

GET /is-initialized (public), POST /initialize (setup wizard, only when uninitialized), POST /reset-db (admin), POST /reindex-documents (admin, RAG reindex), POST /ocr/prewarm (admin).

Quotas & Costs - /api/quota + the cost surfaces (routes/quota.ts, Phases 203/207/209) - F-QUOTA-1

Token quotas (Phase 207): per-user/group, hourly reset (the quotaResetJob sweep).

MethodPathPermissionNotes
GET/quota/meJWTOwn quota state (window usage vs limit)
GET/quota/rollupagency:users:manageRollup across managed users
GET/quota/:userIdagency:users:manageA user's quota state
PUT/quota/:userIdrequireAdminSet/edit a user's token quotas
POST/quota/:userId/resetagency:users:manageManual reset (the hourly sweep also resets)

Costs (Phase 203, server-side per-currency accounting):

MethodPathPermission
GET/workspaces/:id/chats/:chatId/costrequireWorkspaceAccess
GET/workspaces/:id/cost/todayrequireWorkspaceAccess
GET/system/analytics/cost?days=NrequireAdmin
GET/system/analytics/cost-by-modelrequireAdmin

Per-user model policy & BYOK (Phase 209): GET /me/provider-keys (own keys, encrypted at rest), PUT/DELETE /me/provider-keys/:providerId, PUT/DELETE /users/:userId/models/:providerId/:modelName/pricing, PUT /users/:userId/cloud-model-mode. See 17 - Quotas & Costs.

Audit / Event Log - /api/event-logs (routes/eventLogs.ts, authMiddleware + requireAdmin + requireFeature("audit_log_immutable"))

GET with filters (type/user/workspace/date/action), cursor pagination.

Analytics - /api/system/analytics (routes/analytics.ts, authMiddleware + requireAdmin)

GET /tokens, /models, /top-users.

Archives - /api/archives (routes/archives.ts + archivePages.ts, archiveConfig.ts, archiveSearch.ts, archiveGraph.ts, archiveExport.ts, archiveIndex.ts, archiveImport.ts, archiveSchemaTemplates.ts)

GET list, POST (archive:write), GET/PUT/DELETE /:archiveId (archive:delete for delete), POST /from-template, POST /:archiveId/reindex. Pages: GET/POST /:archiveId/pages, GET/PUT/DELETE /:archiveId/pages/:slug. Config, search (hybrid RRF), graph, export, index, import (copy-from-doc, import/:jobId, import/:jobId/callback), schema templates.

OCR - /api/ocr + /api/archives/:id/jobs (routes/ocr.ts, authMiddleware)

OCR catalog at /api/ocr. Archive jobs: GET /archives/:id/jobs, GET /:jobId, POST /:jobId/approve, POST /:jobId/reject, DELETE /:jobId, GET /:jobId/pages/:pageNumber/image (query token auth).

Synthesis - /api/synthesis (routes/synthesis.ts, authMiddleware)

GET /status, GET /pending/count, POST /trigger (archive:write + feature limit), GET /:runId, POST /:runId/approve, POST /:runId/reject, DELETE /:runId, PATCH /:runId/rename.

POST /wiki-write/preview, POST /wiki-write/:runId/approve|reject|undo, GET /wiki-write/history/:archiveId, POST /wiki-write/distill. Links: POST /wikilinks/resolve, GET /wikilinks/:archiveId[/:pageSlug], maintenance GET/POST /wikilinks/maintenance/:archiveId[/merge].

Chat retention - /api/system/chat-retention (routes/chatRetention.ts)

PUT (system:write, confirmDataLoss: true, audited). See 03 - Configuration.

Health - / (routes/health.ts)

GET / (public, { uptime }), GET /api/health (public, { status, checks: { database, collector, disk } }), GET /api/health/rag.

Widget Service - porta 3211 (packages/widget)

GET /health, GET /widget/:id.js (loader), GET /widget/:id (HTML iframe), GET /api/config/:id (branding+trigger+lead), POST /api/config/:id/cache-bust, POST /api/sessions (anonymous session), POST /api/chat/:id/stream (SSE, x-session-token), POST /api/lead/:id (lead capture).

Collector Service - porta 3210 (packages/collector)

GET /api/health, GET /api/ingest/chunks/:documentId, POST /api/ingest (X-Collector-Secret, multipart), POST /api/ingest/query (vector search), DELETE /api/ingest/:documentId, POST /api/ingest/reembed, POST /api/ingest/youtube, POST /api/ingest/wiki-pages, DELETE /api/ingest/wiki-pages/:pageId, POST /api/ingest/archive-page.

v0.28.1 Provenance

StatementSource
The Connectors group + the EDIT arm + OAuth callback + the public webhook routerpackages/server/src/routes/connectors.ts (row-time inventory, 35-02 probe) + CHANGELOG.md v0.28.1 (Added) - F-CONN-2
Quota/costs/BYOK/per-user model policy (Phases 203/207/209)docs/API.md:377-405 (row-time) - F-QUOTA-1
Custom-skill CRUD + the test previewdocs/API.md:358-360 + docs/CUSTOM_SKILLS.md - F-SKILL-1
The instance-slot routes (GET/PUT/DELETE /api/license/instance)docs/API.md:157-159 + docs/ADMIN.md - F-LIC-1

Operational reference - Simmetric Chat v0.28.1 (docs updated 2026-10-02, census SHA `aca5b8ff`).