Technical docs

Settings

Overview

Support reference for `/org-settings`.

Routes and tabs

  • `/org-settings` redirects to `/org-settings/organization`
  • Tabs:
  • `Organization`
  • `AI Providers`
  • `Webchat`
  • `AI Providers` and `Webchat` are visible in the settings nav only for org admins, owners, and developer users who pass the org-admin access check. Direct visits by other users render `AccessDenied`.
  • Shared shell:
  • layout title: `Settings`
  • description: `Manage your organization settings and customizations.`
  • a shared language picker appears above settings sections
  • current picker locales are `English`, `Russian`, `Spanish`, `Ukrainian`, `Serbian`, and `Kazakh`

Organization

  • Page title: `Organization`
  • Description: `Manage your organization's general settings`
  • Current editable items:
  • `Organization Name`
  • `Default AI model`
  • `Debug Mode`
  • For users who can edit organization settings, the Organization page also shows the `Alloy API Keys` card.
  • `Default AI model` picker includes a `Not set` option plus non-realtime, non-TTS, non-STT text models from the shared model catalog.
  • `Logo` upload is present but disabled with `Coming soon`.
  • Save button label: `Save`
  • Permission note:
  • the frontend enables editing only for org `admin` / `owner` users, plus developer users via `canAccessTool({ isOrgAdmin: true })`
  • the backend `PUT /api/organizations/{id}` independently checks org role and rejects non-admin members with `403`
  • Backend/data flow:
  • the page sends `name`, `ai_default_model`, or `is_debug_mode`
  • the route is `PUT /api/organizations/{id}`
  • backend validates `ai_default_model` against the stored AI model catalog when it is non-null
  • the broader update payload also supports provider API keys and `description`, but those fields are not exposed on this page
  • websocket refresh comes through `organization.updated`
  • Runtime note:
  • when an AI teammate or Ally does not have an explicit `model`, runtime resolution now tries the org `ai_default_model` before the system fallback model

Webchat

  • Focus: appearance settings plus live preview.
  • Widget domain choices:
  • `alloy.cx`
  • `alloy.ws`
  • Theme choices:
  • `System`
  • `Light`
  • `Dark`
  • `Custom`
  • Section labels:
  • `Appearance`
  • `Widget domain`
  • `Theme`
  • `Live Preview`
  • Current UI controls:
  • minimized widget: `Bubble color`, `Icon color`
  • maximized widget: `Chat background`, `Primary color`
  • customer messages: `Bubble color`, `Text color`
  • agent messages: `Bubble color`, `Text color`
  • `Custom CSS` textarea
  • `System` mode preview tabs for `light` and `dark`
  • Footer actions:
  • `Reset to defaults`
  • `Save changes`
  • Confirmed backend values:
  • `mode`: `system`, `light`, `dark`, `custom`
  • `widgetDomain`: `default`, `proxy`
  • Permission note:
  • the Webchat settings page is frontend-gated by the org-admin access check
  • widget settings are organization-scoped and authorized by backend checks
  • Backend/data flow:
  • `GET /api/organizations/{id}/settings/webchat-widget-settings` returns `{ settings, defaults }`
  • `POST /api/organizations/{id}/settings/webchat-widget-settings` upserts the stored delta and returns merged `{ settings, defaults }`
  • reset-to-defaults is implemented as `POST` with an empty body
  • defaults include additional runtime fields not currently editable in the page:
  • `opacity`
  • `primaryTextColor`
  • `secondaryTextColor`
  • `borderColor`
  • `systemMessageColor`
  • those extra fields are still part of the backend schema and are consumed by the widget runtime if present
  • Preview/runtime notes:
  • the preview loads `${NEXT_PUBLIC_API_URL}/widget/alloy-webchat-widget.js`
  • it initializes the widget with the org `public_api_key`
  • `widgetDomain: proxy` is used by backend snippet generation to switch from `API_DOMAIN` to `API_PROXY_DOMAIN`

AI Providers

  • Route: `/org-settings/api-keys`
  • Nav label: `AI Providers`
  • Page title: `AI Providers`
  • Description: `Connect LLM providers and manage provider credentials`
  • Cards and sections:
  • `Provider API Keys`
  • `OpenAI Codex`
  • `Custom provider`
  • Provider rows:
  • `OpenAI`
  • `OpenRouter`
  • `Google`
  • `DeepSeek`
  • `Anthropic`
  • Standard provider key actions:
  • type key
  • `Save API Key`
  • `Copy to clipboard` after save
  • `Clear API Key`
  • Saved provider keys stay masked in the input.
  • `Custom provider` is an organization-scoped OpenAI-compatible connection:
  • fields: `API key` and `Base URL`
  • both values are required before `Save` is enabled and the provider becomes active
  • after save, the key is masked and the Base URL is read-only
  • `Copy to clipboard` reveals the stored key through a dedicated backend request and copies it
  • `Reset` clears both values; the reset toast offers an undo action while the previous credentials are retained for restoration
  • Alloy key rows on the Organization page:
  • `Public`
  • `Private`
  • Alloy key behavior:
  • public key is shown directly and can be copied
  • private key stays masked in the UI and is fetched only when the user clicks copy
  • `OpenAI Codex` card currently supports three states:
  • `Connect`
  • authorization flow with a copyable `Code`, countdown, and `Open authorization page`
  • `Disconnect` for an active connection
  • Permission note:
  • the `AI Providers` and `Webchat` settings pages are frontend-gated by the org-admin access check
  • standard provider key save and clear still go through `PUT /api/organizations/{id}`, which requires org `owner` or `admin`
  • Custom provider list, update, and key-reveal routes require organization admin access on the backend
  • private Alloy key copy is available from the Organization page for authorized organization users who can edit org settings
  • Backend/data flow:
  • standard provider credentials save and clear through `PUT /api/organizations/{id}`
  • organization provider routes are:
  • `GET /api/organizations/{id}/providers`
  • `PATCH /api/organizations/{id}/providers/custom`
  • `POST /api/organizations/{id}/providers/custom/api-key/reveal`
  • `POST /api/organizations/{id}/providers/codex/connection-attempts`
  • `GET /api/organizations/{id}/providers/codex/connection-attempts/current`
  • `POST /api/organizations/{id}/providers/codex/revoke`
  • runtime uses a matching saved provider key before falling back to the Alloy system key for the same provider
  • Custom models use the active organization Custom API key and Base URL; if that organization connection is unavailable, runtime falls back to the system Custom provider configuration
  • a Custom provider row is active only while both its encrypted API key and Base URL are present; otherwise it is stored as revoked
  • Codex-backed models resolve their organization credential from the active Codex provider connection
  • active Codex provider rows can carry `refresh_after_at`; the backend refresh job refreshes due Codex credentials and publishes `organization_ai_provider.updated`
  • failed Codex credential refresh or credential decryption marks the provider `failed` and clears the stored payload
  • usage with org-saved provider keys is still written to token history and cost reporting, but it does not reduce org `available_tokens`
  • org state on this page stays in sync through `organization.updated`, `organization_ai_provider.updated`, and `organization_ai_provider_connection_attempt.updated`

Not in this settings shell

  • `models` and `voices` are separate tools, not `/org-settings/*`
  • `/system-settings` is separate from org settings

Start building your AI team