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