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.
| Outcome | Status | Condition |
|---|---|---|
| Bot not found | 404 | No bot with bot_id |
| Invalid API key | 401 | bot.widget_api_key unset or mismatched |
| Token generation failed | 500 | LiveKit token mint error |
| Bot dispatch failed | 503 | No fleet / no healthy worker / dispatch error |
| Success | 201 | {server_url, participant_token} |
Flow
- Room name:
widget-{bot_id}-{uuid12}— unique per call. - Token:
_generate_livekit_tokenmints anAccessTokenwith identitywidget-user-{uuid8}, nameWebsite Visitor, and aroom_joingrant scoped to that room. Returns(livekit_url, jwt). - Dispatch:
_dispatch_bot_to_roomreadscore_fleet, callspick_fleet_server(see fleet routing), andPOST {fleet}/livekit/widgetwithX-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.Related docs
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.