/api/v1/sip routes are the telephony control-plane surface CXB API exposes to two consumers: CXB Core (internal SIP lookups, protected by X-CXB-Core-Secret) and CRMs/admins (dialout, protected by API key or JWT).
These routes live in the API service’s SIP module, with API-key auth and the SIP-header service.
Endpoints
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/v1/sip/lookup?number= | X-CXB-Core-Secret | Inbound DID → {bot_id, carrier_id, did_id} |
GET | /api/v1/sip/outbound-trunk?from_number= | X-CXB-Core-Secret | Outbound trunk + rate limit for dialout |
POST | /api/v1/sip/dialout | X-API-Key or Bearer JWT | Trigger an outbound call |
GET lookups verify the shared internal secret, rejecting any request whose X-CXB-Core-Secret header does not match the configured core_secret with 403. They delegate to the carrier-service lookup_did and lookup_outbound_trunk helpers, returning 404 when nothing matches.
Dual authentication
/dialout depends on the require_admin_or_api_key dependency:
- API keys are looked up by SHA-256 hash (
_hash_api_key); raw keys are never stored. See API keys. last_used_atis updated viaasyncio.create_task, so it never blocks the dialout path.expires_atis coerced to UTC; a malformed expiry yields403 API key has invalid expiry.
Dialout flow
proxy_dialout body (DialoutRequest): bot_id (required), to_number (required), from_number?, connected_event?, variables?.
- Load
core_fleetfromsystem_settings;503if empty. pick_fleet_serverchooses the healthiest fleet host;503if none healthy. See fleet routing.- Reject
422if bothvariablesandconnected_eventare sent. - Map
variables→connected_event(CRM-friendly alias) in the proxied payload. - Inject
config_url = <request base URL>/api/v1/configso the shared fleet fetches config from this CXB API instance. POST {fleet}/livekit/dialoutwithX-CXB-Core-Secretand a 60s timeout. A non-200 is surfaced with the fleet’s status code and itserrorfield.
The
variables alias is the field CRMs send. Internally CXB Core only understands connected_event, so CXB API renames it before proxying. Sending both is a client error (422).SIP header passthrough
Inbound SIP X-headers are turned into prompt variables by the SIP-header service, consumed by the config service (filter_sip_headers(... config=bot["sip_header_config"])). The carrier’s inbound trunk only forwards the headers in DEFAULT_INBOUND_HEADERS_TO_ATTRIBUTES; the bot’s sip_header_config then gates which of those reach the prompt.
filter_sip_headers behaviour:
| Behaviour | Detail |
|---|---|
| Disabled config | Returns empty {headers, variables, transfer_headers} |
| Candidate filter | Only keys starting with sip.h., x-, or x_ are considered |
| Normalization | normalize_header_key strips the sip.h. prefix, lowercases, collapses non-alphanumerics to _ |
| Variable naming | variable_name_for_header → sip_header_<normalized> |
| Value cap | Values truncated to max_value_length (256 chars) |
| Allowlist | Only headers in allowed_headers are emitted |
| Transfer | transfer_passthrough_headers (subset of allowed) are echoed on transfer |
Related docs
Carriers & trunks
DID → trunk mapping and outbound trunk selection.
API keys
CRM API-key lifecycle and hashing.
Fleet routing
Best-server selection and
config_url passthrough.CRM dialout API
Operator/CRM-facing dialout usage.