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 into preferences.device. When omitted the response shape is unchanged: device is {} and deviceId is null, while global and knownDevices are still returned in full. knownDevices is deliberately not gated on deviceId — 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 null deletes a key.
  • Scopes: global keys (theme, font, background treatment) sync everywhere. device keys (panel widths, UI scale, collapse state) are stored per deviceId, because pixel geometry chosen on a 27-inch display is wrong on a laptop.
  • Conflict resolution: global is last-write-wins on updatedAt; a patch older than the stored state is ignored and reported as result.global.staleIgnored. device writes 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.
    • deviceId is required whenever device is present (400 otherwise).
    • Unknown or malformed keys are dropped, not stored, and are listed in result.*.rejected so a client can see the write was refused.
    • Custom background media is not synced — it lives in browser IndexedDB. Only the useCustomBackground / bgOpacity / bgBlur treatment 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: 400 malformed body / missing deviceId / non-numeric updatedAt; 404 user not found; 413 payload 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 data object, not at the root level.
  • Provider status values are "healthy" or "error" (not "connected").
  • Each provider object has a provider field (lowercase provider name), not name or id.
  • Failed providers include an error field instead of details.

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 202 first, then starts the drain — the 2s grace period guarantees the response flushes before the socket dies. Backend is back in ~10–20 seconds. 409 if 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": {}
}