Base URL
http://localhost:3333/api/· Authentication · Conventions
User Routes
Base path: /api/users
Health Check
GET /health
- Authentication: None
- Description: Check if the user service is running
- Response:
{
"status": "OK"
}Get User Stats
GET /user-stats
- Authentication: Required
- Description: Get user statistics
- Response:
{
"agents": 5,
"workflows": 10,
"tools": 3,
"goals": 2,
"executions": 100,
"storageUsed": "1.2GB"
}Get User Settings
GET /settings
- Authentication: Required
- Description: Get user settings
- Response:
{
"theme": "dark",
"language": "en",
"notifications": {
"email": true,
"push": false
},
"preferences": {}
}Update User Settings
PUT /settings
- Authentication: Required
- Body:
{
"theme": "light",
"language": "es",
"notifications": {
"email": false,
"push": true
}
}- Response:
{
"success": true,
"settings": {
"theme": "light",
"language": "es",
"notifications": {
"email": false,
"push": true
}
}
}Get User Preferences
GET /preferences
- Authentication: Required
- Description: Cross-device UI preferences (theme, font, panel geometry). Distinct from
/settings, which holds account-level AI configuration and is replace-on-write. - Query params:
deviceId(optional) — 1-64 chars of[A-Za-z0-9_-]. When supplied, that device's geometry is resolved intopreferences.device. When omitted the response shape is unchanged:deviceis{}anddeviceIdisnull, whileglobalandknownDevicesare still returned in full.knownDevicesis deliberately not gated ondeviceId— a caller listing a user's devices has no device of its own to name.
- Response:
{
"success": true,
"preferences": {
"global": { "currentTheme": "dark", "fontFamily": "sans", "bgOpacity": 90 },
"device": { "uiScale": 100, "leftPanelWidth": 384 },
"deviceId": "dev-abc123",
"updatedAt": 1786029683945,
"knownDevices": [
{ "deviceId": "dev-abc123", "label": "iMac", "updatedAt": 1786029683945, "current": true }
]
}
}Update User Preferences
PUT /preferences
- Authentication: Required
- Description: Merges a patch into the stored preferences. Send only the keys that changed; unsent keys are preserved, so an older client cannot erase a key it does not know about. An explicit
nulldeletes a key. - Scopes:
globalkeys (theme, font, background treatment) sync everywhere.devicekeys (panel widths, UI scale, collapse state) are stored perdeviceId, because pixel geometry chosen on a 27-inch display is wrong on a laptop. - Conflict resolution:
globalis last-write-wins onupdatedAt; a patch older than the stored state is ignored and reported asresult.global.staleIgnored.devicewrites always apply, being uncontended by construction. - Body:
{
"global": { "currentTheme": "cyberpunk", "fontFamily": null },
"device": { "leftPanelWidth": 420 },
"deviceId": "dev-abc123",
"deviceLabel": "iMac",
"updatedAt": 1786029683945
}- Notes:
updatedAt(epoch ms) should be the moment the user acted, not the moment the request was built. Defaults to server time when omitted.deviceIdis required wheneverdeviceis present (400 otherwise).- Unknown or malformed keys are dropped, not stored, and are listed in
result.*.rejectedso a client can see the write was refused. - Custom background media is not synced — it lives in browser IndexedDB. Only the
useCustomBackground/bgOpacity/bgBlurtreatment flags cross devices.
- Response:
{
"success": true,
"preferences": {
"global": { "currentTheme": "cyberpunk" },
"device": { "leftPanelWidth": 420 },
"deviceId": "dev-abc123",
"updatedAt": 1786029683945,
"knownDevices": []
},
"result": {
"global": { "applied": ["currentTheme"], "deleted": ["fontFamily"], "rejected": [], "staleIgnored": false },
"device": { "applied": ["leftPanelWidth"], "deleted": [], "rejected": [], "deviceId": "dev-abc123" },
"evictedDevices": []
}
}- Errors:
400malformed body / missingdeviceId/ non-numericupdatedAt;404user not found;413payload exceeds 64 KB.
Sync Token
POST /sync-token
- Authentication: Required
- Description: Sync user token across services
- Response:
{
"success": true,
"message": "Token synced successfully"
}Get Token Status
GET /token-status
- Authentication: None
- Description: Get current token status
- Response:
{
"valid": true,
"expiresIn": 3600,
"refreshRequired": false
}Get Connection Health
GET /connection-health
- Authentication: Required
- Description: Get health status of all provider connections
- Response:
{
"success": true,
"data": {
"overall": "healthy|degraded",
"healthyConnections": 51,
"totalConnections": 52,
"timestamp": "2026-01-01T15:42:40.838Z",
"providers": [
{
"provider": "openai",
"status": "healthy",
"lastChecked": "2026-01-01T15:42:39.786Z",
"details": {}
},
{
"provider": "anthropic",
"status": "healthy",
"lastChecked": "2026-01-01T15:42:37.303Z",
"details": {}
},
{
"provider": "twitter",
"status": "error",
"lastChecked": "2026-01-01T15:42:40.643Z",
"error": "Failed to retrieve access token from remote auth service."
}
]
}
}Important:
- The response wraps data in a
dataobject, not at the root level. - Provider status values are
"healthy"or"error"(not"connected"). - Each provider object has a
providerfield (lowercase provider name), notnameorid. - Failed providers include an
errorfield instead ofdetails.
Get Single Provider Health
GET /connection-health/:providerId
- Authentication: Required
- Parameters:
providerId(path): Provider ID
- Description: Get health status of a specific provider
- Response:
{
"id": "openai",
"name": "OpenAI",
"status": "connected",
"lastCheck": "2024-01-01T00:00:00Z",
"latency": 150,
"details": {}
}Get Connection Health Stream
GET /connection-health-stream
- Authentication: Required (via token query parameter)
- Parameters:
token(query): JWT token
- Description: Get real-time connection health updates via SSE
- Response: Server-sent events stream
Get Security Policy
GET /security-policy
- Authentication: Required
- Description: The current user's security policy
- Response: Security policy object
Update Security Policy
PUT /security-policy
- Authentication: Required
- Description: Update the current user's security policy
- Response: Updated security policy object
Reset Security Policy
DELETE /security-policy
- Authentication: Required
- Description: Reset the current user's security policy to defaults
- Response: Confirmation object
Get Security Audit
GET /security-audit
- Authentication: Required
- Description: Security audit information for the current user
- Response: Security audit object
System Routes
Base path: /api/system
System-level operations: status and restart.
Get System Status
GET /status
- Authentication: None — intentionally unauthenticated: the frontend polls this while the backend drains/reboots, and the Electron supervisor may check it too. Exposes nothing sensitive (state/pid/uptime).
- Response: RestartManager status object (state, pid, uptime)
Restart Backend
POST /restart
- Authentication: Required
- Description: Initiates a backend restart. Responds
202first, then starts the drain — the 2s grace period guarantees the response flushes before the socket dies. Backend is back in ~10–20 seconds.409if a restart is already in progress. - Body:
{
"reason": "optional reason string"
}- Response (202):
{
"success": true,
"message": "Restart initiated. Backend will be back in ~10-20 seconds.",
"gracePeriodMs": 2000
}Admin Routes
Base path: /api/admin
Administrative operations.
Get Client Versions
GET /client-versions
- Authentication: None
- Description: Inspected CLI/client versions for supported providers
- Response:
{
"success": true,
"providers": {}
}Refresh Client Versions
POST /client-versions/refresh
- Authentication: None
- Description: Re-inspects all client versions
- Response:
{
"success": true,
"refreshed": {}
}