Cumulus TalosDocs
Open Talos
On this page

Phone

Phone agents call out over your own carrier: connect a SIP trunk, import the numbers you own on it, and place calls from them. Talos does not sell numbers or bill for carrier minutes.

Bring your own carrier

In Twilio

  1. Create an Elastic SIP trunk and turn on Secure Trunking: Talos dials over TLS (port 5061) with SRTP media.
  2. Under Termination, set a Termination SIP URI (<name>.pstn.twilio.com) and attach a Credential List (a username and password). IP access control lists on their own are not supported: Talos authenticates with those digest credentials.
  3. Under Numbers, add every number you will call from.

In Talos

The simplest path is Talos: Phone numbers → Connect trunk, then Import number for each caller ID. It stores the password as a secret for you, so the password never passes through a script or an assistant. The API steps are below.

Setting up telephony takes an admin key. A trunk is your carrier's SIP termination (twilio_elastic_sip or generic_sip) with digest credentials: the username, and the password stored as a secret of kind sip_auth. Its host must resolve to public addresses.

Connect a trunk and import a number

Example
# 1. Store the trunk's SIP digest password as a secret (admin key).
PUT /api/v1/secrets/twilio-sip          { "kind": "sip_auth", "value": "…" }
#    → { "id": "twilio-sip", "current_version": "…", … }

# 2. Connect the trunk. Talos dials out through it with these credentials.
POST /api/v1/telephony/trunks
{ "trunk_id": "twilio-main", "name": "Twilio main", "provider": "twilio_elastic_sip",
  "termination_uri": "acme.pstn.twilio.com", "auth_username": "talos",
  "auth_secret": { "id": "twilio-sip", "version": "<current_version>" } }

# 3. Import a number you own on that trunk, and assign it to an agent.
POST /api/v1/telephony/numbers
{ "e164": "+14155550100", "trunk_id": "twilio-main", "nickname": "Collections line",
  "outbound_agent_id": "<phone agent id>" }
#    → { "number_id": "…", "state": "pending" | "ready", … }
  • A number is pending until it is provisioned, then ready. Calls from a pending number are refused with 503 provider_unavailable; retry once it is ready.
  • outbound_agent_id records which published agent calls from the number; an agent with a number assigned cannot be deleted.
  • Inbound calls to your numbers are not available yet: inbound_agent_id and inbound trunks are refused.
  • Trunks and numbers belong to one environment: connect them in your sandbox to test calls there, and again in production.

What Cumulus sets up first

Cumulus staff set each environment's concurrent call cap and open it for runs. Before that, connecting a trunk or importing a number is refused with tenant_not_configured, and calls with tenant_not_configured or tenant_disabled (403 forbidden, in details.reason). GET /api/v1/runs/capacity shows the limit and whether admission is open. Ask your Cumulus contact to set voice capacity and open run admission for the environment (its slug and tenant_id are in GET /api/v1/environments). Your calls always go out on your own trunk; you never need a Cumulus trunk.

OperationMCP toolKey rolePurpose
GET /api/v1/telephony/trunkstrunks_listviewerList BYOC SIP trunks
POST /api/v1/telephony/trunkstrunks_createadminConnect a BYOC SIP trunk
PATCH /api/v1/telephony/trunks/{trunk_id}trunks_updateadminUpdate a BYOC SIP trunk
DELETE /api/v1/telephony/trunks/{trunk_id}trunks_deleteadminDisconnect a BYOC SIP trunk
GET /api/v1/telephony/numbersnumbers_listviewerList BYOC phone numbers
POST /api/v1/telephony/numbersnumbers_importadminImport a phone number from a connected trunk
PATCH /api/v1/telephony/numbers/{number_id}numbers_updateadminAssign agents or rename a phone number
DELETE /api/v1/telephony/numbers/{number_id}numbers_releaseadminRelease a phone number

Caller ID: from

A phone run picks its caller ID and trunk like this:

  1. The run's from, or else the from the agent was published with (agent.telephony). With neither, the run is refused: 400 invalid_request.
  2. If that number is one you imported, the call goes out on the number's trunk.
  3. Otherwise it goes out on the trunk the agent was published with; an agent with no trunk is refused with 409 capability_unavailable.
  4. The trunk must be yours, enabled, and allowed to present that number; if not, 403 forbidden with details.reason: "trunk_not_authorized".

Note

The simplest setup: import each number you call from, and pass it as from. See Place a phone call.

Set an agent's trunk and default caller ID with the agent.telephony edit. POST …/draft/validate warns before any call would be refused: telephony_trunk_unknown (no such trunk in this environment), telephony_from_not_imported (the caller ID is not an imported number) and telephony_number_pending (the number is still being set up). Warnings do not block publishing, so you can test in the browser or with simulated calls before your trunk is ready.

Every phone run is a real call

test: true keeps a run out of billing, webhooks and triggers, but it still dials. Test with simulated calls or a browser test session first, and call numbers you own.

During and after a call

  • phone_state follows the call: admitted, preparing, awaiting_sip, dialing, ringing, active, terminating, ended, rejected, expired, setup_failed.
  • Events such as phone.amd_verdict, phone.voicemail and phone.transfer report answering-machine detection, voicemail and transfers.
  • On an outbound call where the agent speaks first, it greets once the person has picked up: after their first words ("Hello?") and a pause, or after 1.5 s of quiet on the line, and never later than 5 s after the call connects. Those first words stay in the transcript. beginMessageDelayMs adds to the wait. Set openerWaitsForCallee: false (Talos: "Wait for the person to answer") to greet as soon as the call connects. Inbound calls and browser tests don't wait.
  • With voicemail or IVR detection set to hang up, the agent greets at answer, before detection decides, so a voicemail box can record that first line. It must be fixed text that names no one and no debt, amount or collector (for example "Hi, this is Alex on a recorded line."); ask for the person in the next node. Publishing refuses any other opener (opener_not_neutral on the start node), and nothing else is said until detection finds a person. The finding carries a fix in fixes that puts such a greeting in front of your opener: send its edits with drafts.edit (Talos's Problems list does this with one click). A leave-message policy waits for detection before its first word, so its opener is not limited.
  • Phone agents record both channels by default. GET …/recording returns a link that expires after five minutes; GET …/transcript the turns with their timing.
  • A recording never ends or shortens a call. If recording cannot start by the time the call is answered, or stops partway, the call continues unrecorded, the run's recording.updated event reports failed with a reason, and GET …/recording reads failed.
  • Concurrent calls are capped per organization (GET /api/v1/runs/capacity, channel phone).

Voices

GET /api/v1/voices lists the speech-to-text and text-to-speech models and the voices an agent can use, optionally for one language (en or es). Set them on a draft with the agent.provider edit.

OperationMCP toolKey rolePurpose
GET /api/v1/voicesvoices_listviewerList the speech models and platform TTS voices an agent can use
Content version a452333bMarkdown source
Phone · Cumulus Talos docs