/dashboard/bots/:id is src/pages/BotDetail.tsx. It has three faces: a read-only view mode with Details/Integration tabs, an edit mode that reuses the create wizard, and a test-call modal.

Loading

On mount, loadBot fetches the bot and its WSS URL in parallel:
  • GET /api/v1/bots/:id
  • GET /api/v1/bots/:id/wss-url (best-effort)
It also queries GET /api/v1/campaigns?status=running and filters for campaigns using this bot, to show a config-lock banner.

Header Actions

ActionBehavior
Test CallOpens TestCallModal
ClonePOST /api/v1/bots/:id/clone, warns calls/campaigns/DID mappings are not copied
EditEnters edit mode (deserialize(bot) then the wizard)
DeleteDELETE /api/v1/bots/:id after confirm
A WSS URL panel (with copy button) and a campaign-lock banner render below the header when applicable.

Cache Controls

Two cache sections sit above the tabs:
SectionEndpointsNotes
Post-Call CachePOST /api/v1/bots/:id/post-call-cache/{enable|disable|refresh}Refresh disabled unless an analysis or QC prompt exists
Live Prompt CachePOST /api/v1/bots/:id/live-prompt-cache/{enable|disable|refresh}Only shown for non-policy bots; refresh requires a static system prompt
Each shows config readiness (prompts configured, version override, refreshed-by) and an enable/disable + refresh button pair. The Live Prompt Cache section is hidden when the bot uses a Conversation Policy engine type.

Edit Mode

Edit mode renders the same StepWizard and step components as the create wizard, driven by the same useBotForm hook (here used with deserialize). The STEPS array and errorToStep mapping mirror BotCreate. Save calls validate(), then PUT /api/v1/bots/:id, refreshing the page data on success.

View Mode: Details Tab

The Details tab composes SectionGroup/Section/ViewField blocks:
GroupSections
Core ConfigurationVoice Stack (STT/LLM/TTS), System Prompt, Opening Message, Conversation Policy (when enabled)
Behavior & RuntimeRuntime Config (max duration, re-engagement, VAD, interruption) + re-engagement messages
Advanced FeaturesTools, Transfer Call, SIP Headers, Analysis Prompts, CRM Pre-fetch, Post-Call Push (each rendered only when present)

View Mode: Integration Tab

The Integration tab is src/components/bot/IntegrationTab.tsx — an auto-generated CRM integration guide. It has four sections:
  1. Quick Start — copy-paste snippets for curl, Python, and Node.js, built by buildSnippets and rendered through CodeSnippet.
  2. Request Reference — the POST {VITE_API_URL}/api/v1/sip/dialout endpoint, headers, body field table, this bot’s variables, a sample response, and an error-code table.
  3. Post-Call Webhook — the configured push URL/method/masked token and a sample payload built from the key_mapper, with the analysis prompt in a collapsible block.
  4. Variable Reference — expandable cards for the call.*, crm.*, result.*, analysis.*, qc.*, and system.* namespaces.

Variable Extraction

extractCallVariables regex-matches {{...}} tokens in system_prompt and opening_message (skipping system.*), defaulting bare tokens to the call namespace. When a Conversation Policy is enabled, it also pulls every *_field value from the policy config as a call.* variable. The snippet builder passes these to the CRM as bare keys (e.g. due_amount, not call.due_amount); CXB API resolves the namespace so {{call.X}} and {{crm.X}} both work from the same payload.

CodeSnippet

components/bot/CodeSnippet.tsx is a tabbed code block: one tab per snippet label, a copy button with a transient “Copied” state, and a <pre> body. It is reused for the Quick Start snippets, the sample response, and the sample webhook payload.

Test Call Modal

components/bot/TestCallModal.tsx initiates a real outbound test call.
SurfaceBehavior
Test ViaChoose LiveKit SIP or Exotel Connect (only transports with options appear)
Carrier + DID (SIP)Loads synced carriers with outbound/both DIDs
Exotel NumberLoads Exotel test DIDs; blocks if setup incomplete
Phone Number (To)E.164 or STD, validated by regex
Test Options (SIP)Toggles for CRM Pre-fetch and Post-call Push
Template VariablesInputs for each {{...}} var found in the dynamic/system prompt + opening message + policy fields; “Inject mock data” toggle
On start (SIP), it builds a connected_event (routing crm namespace vars into a _mock_crm block, setting _skip_prefetch/_skip_post_push flags from the toggles) and calls POST /api/v1/sip/dialout. It then polls GET /api/v1/calls/:id every 2s for up to 2 minutes, showing live status via describeTestCallState. Exotel test calls go to POST /api/v1/integrations/exotel/dids/:id/test-call. Selections (carrier, DID, number, variables) are saved back via PUT /api/v1/bots/:id/test-data for next time.

Create Bot Wizard

The steps edit mode reuses.

Tool Builder

How the tools shown here are built.

Call Detail

Reviewing the test call afterward.

Post-call webhook

Full key_mapper variable reference.