The web widget lets a website visitor place a browser call to a bot over LiveKit. CXB API issues the LiveKit participant token and dispatches a CXB Core worker into the room. This page covers the server side; the CXB Core room handler is documented under CXB Core widget transport. The widget token logic lives in the API service’s widget route.

Endpoint

POST /api/v1/widget/token (status 201) — public, no JWT. Authenticated by a per-bot widget API key, not platform auth. A matching OPTIONS /token returns CORS preflight headers (Access-Control-Allow-Origin: *). Request body (WidgetTokenRequest): bot_id, api_key.
OutcomeStatusCondition
Bot not found404No bot with bot_id
Invalid API key401bot.widget_api_key unset or mismatched
Token generation failed500LiveKit token mint error
Bot dispatch failed503No fleet / no healthy worker / dispatch error
Success201{server_url, participant_token}
All responses carry the CORS headers so the widget can call cross-origin.

Flow

  • Room name: widget-{bot_id}-{uuid12} — unique per call.
  • Token: _generate_livekit_token mints an AccessToken with identity widget-user-{uuid8}, name Website Visitor, and a room_join grant scoped to that room. Returns (livekit_url, jwt).
  • Dispatch: _dispatch_bot_to_room reads core_fleet, calls pick_fleet_server (see fleet routing), and POST {fleet}/livekit/widget with X-CXB-Core-Secret (10s timeout). The token is only returned to the browser after a successful dispatch, so the visitor never joins a room with no bot.
The widget API key is stored per-bot as bot.widget_api_key and is independent of the CRM API keys in the api_keys collection. It gates only this token endpoint.

Widget transport (CXB Core)

What CXB Core’s /livekit/widget does in the room.

Fleet routing

Best-server selection used for widget dispatch.

API keys

The separate CRM API-key system (not the widget key).

CXB API overview

Control-plane responsibilities.