Exotel calls reach CXB Core over a WebSocket the Exotel App Bazaar Voicebot applet opens. CXB API owns the Exotel integration record: provider credentials, the DID list, the generated per-bot WebSocket URLs, and a “place a test call” helper that drives Exotel’s connect-to-flow API. The integration logic lives in the API service’s integrations route and integration service. The integration is stored as a single document {type: "exotel"} in the integrations collection.

Endpoints

All under /api/v1/integrations. Credential/DID writes require super_admin; test-call reads require admin.
MethodPathRolePurpose
GET/exotelsuper_adminGet integration (credentials masked to a configured flag + account_sid)
PUT/exotelsuper_adminUpsert credentials (account_sid, api_key, api_token, api_base_url)
POST/exotel/didssuper_adminAdd a DID
PUT/exotel/dids/{did_id}super_adminUpdate DID label/bot_id/flow_url
DELETE/exotel/dids/{did_id}super_adminRemove a DID
GET/exotel/test-call-optionsadminSanitized DIDs usable from the test-call UI
POST/exotel/dids/{did_id}/test-calladminPlace a customer test call via Exotel

Data model

ExotelDID fields: number, label, bot_id, flow_url. The response adds a derived websocket_url. The websocket_url is generated from the fleet base, not stored:
  • _get_fleet_wss_base takes the first entry of core_fleet, swaps https→wss / http→ws (or wss://localhost if the fleet is unset).
  • _websocket_url{fleet_wss_base}/exotel/{bot_id} when a bot_id is attached, else empty.
This is the URL operators paste into the Exotel Voicebot applet so the call reaches CXB Core’s Exotel transport.
The integration response never returns api_key/api_token. credentials_configured is true only when account_sid, api_key, and api_token are all present (_credentials_configured); status is configured/not_configured accordingly. CXB Core does not need Exotel credentials — call control is flow-based.

Test call

start_exotel_test_call uses Exotel’s connect-to-flow REST API to ring a customer and bridge them into the configured flow: Request details:
AspectValue
API URL{api_base_url}/v1/Accounts/{account_sid}/Calls/connect (base normalised, defaults https://api.exotel.com)
AuthHTTP Basic api_key:api_token
Fromnormalised to_number (the customer)
CallerIdthe DID number
Urlthe DID flow_url
CallTypetrans
CustomFieldcxb-test:{did_id} (truncated to 128 chars)
Number normalisation (_normalise_exotel_from_number) maps Indian formats to +91 E.164: a bare 10-digit [6-9]…, 91…, or 0091…. Responses are parsed from JSON first, then XML, extracting call_sid and provider_status. Exotel errors (RestException/Message) surface as 502.
A DID is only test_ready when credentials are configured and the DID has a flow_url. Adding the Exotel Flow URL is required before a test call; otherwise start_exotel_test_call raises 400.

Exotel transport (CXB Core)

How CXB Core handles the Exotel WebSocket and the /exotel/{bot_id} URL.

Fleet routing

The core_fleet list that seeds the generated WebSocket base.

Carriers & trunks

SIP carriers, the non-Exotel telephony path.

Settings

Where core_fleet is configured.