Skip to main content
A connection file holds environment variable names. This page is about the values behind them: where each one lives in your Twilio account, and which key it belongs to. It also covers the console setup those values assume, because a correct connection file over a half-configured trunk still gets you nothing. On this page:
Unmute never buys a number, creates a trunk, or changes anything on your carrier account, at compile time or afterward. Every value below is one you set yourself, in the Twilio Console.

Give each route its own number

A number attached to a SIP trunk ignores its voice configuration completely, and does so silently. So one number cannot serve a TwiML Bin and a SIP trunk at the same time. If you want both routes live, buy a second number: You can also swap a single number back and forth, and the last step of the trunk setup below covers that. Two numbers is less work after the first day.

Which values you need depends on the route

The two groups are different credentials, not two names for one thing. The account trio identifies your account to Twilio’s REST API. The four SIP values are one trunk’s own dial-out settings, and they live in a different part of the console.

Every key a connection takes

Three keys. The first two pick the route, and the third names the variables that hold its values.
sip | connector | cloud-websocket | daily-sip
required
The mechanism that carries the call. It decides which environment keys the file accepts, so changing it changes the group of values you need.
twilio | telnyx | plivo
required
The carrier account behind the route. twilio on every route on this page.
route key to environment variable name
Which variable holds each value. The keys on the left are fixed by the route: account_sid, auth_token and from_number for the account trio, sip_address, sip_username, sip_password and from_number for the SIP route. A key from another route is refused, and the refusal lists the set this route accepts.
The names on the right are yours, and each one is UPPER_SNAKE: an uppercase letter, then only uppercase letters, digits and underscores. The compiler never reads a value, so a package with connections validates and compiles with no credentials present anywhere.

First, a voice-capable number

Phone Numbers, Manage, Buy a number, with the Voice capability. Skip this if you already own the number you want the agent to use. Whatever you buy or already own is the value of from_number (or SIP_FROM_NUMBER on the SIP route). It is also the caller identity the person you dial sees, and voice capability is the whole requirement on it.

The account trio: Pipecat cloud-websocket and the LiveKit connector

These two routes talk to Twilio’s REST API in your name, so they need the account credentials.
connections/twilio_voice.yaml
The names on the right are yours to choose. Those three are what every Twilio example in the repository uses, so one .env drives all of them.

Pointing the number at the agent

This part differs by route, and it is the part to get right:
  • cloud-websocket: the number points at a static piece of TwiML in the console, which streams the call to Pipecat Cloud. There is no URL of yours to configure, because nothing of yours is hosted. Your build’s generated README dictates the exact markup, including the regional stream address. That address comes from the region in your targets.yaml. Pipecat over Twilio walks the whole route, including the organisation slug that is the most common thing to get wrong. - connector: the number’s voice webhook points at POST /telephony/inbound on the public URL of the service you deploy.
Take the number off any SIP trunk before using it on one of these routes. A number attached to a trunk ignores its voice configuration completely, and does so silently, so the markup or webhook you set would simply never be consulted.

The four SIP values: the LiveKit sip route

The LiveKit sip route reads four values from an Elastic SIP Trunk: the termination domain, the credential’s username and password, and the attached number. Setting the trunk up is a console walkthrough of its own, and it lives on LiveKit over Twilio, together with the LiveKit records the call needs afterwards. Two settings on that trunk decide whether a transfer works: Call Transfer (SIP REFER) with Enable PSTN Transfer, and the caller ID below.

Caller ID for a transfer target

A cold transfer is a SIP REFER: Twilio receives it and places a new call to the destination. The trunk decides what caller ID that new call presents, and the two choices behave very differently. Transferee is the nicer behaviour, because the person receiving the transfer sees the customer rather than your own line. It only works where the receiving carrier tolerates a caller ID that belongs to nobody on your account. Present a Spanish mobile number from a UK trunk to a Spanish carrier and it is rejected on the spot. How that failure looks, so you recognise it rather than debugging your agent:
  • The agent logs cold transfer failed after 0s: SIP call failed: 486 Busy Here.
  • Twilio’s call log shows a child call under the original call, with the original caller’s number in From, status Busy, duration 0 sec, cost blank, and no PCAP.
Zero seconds and no cost means the leg was rejected as it was offered and never reached the destination, so nothing rang and nobody was busy. Switch the trunk to Transferor and place the call again. A genuine busy signal costs time and money, and the record shows both.

If your trunk is in a Twilio Region

Twilio can hold resources in a region such as Ireland (IE1) rather than in the default one. If you set a number’s Active Region and create the trunk there, three things change:
  • The trunk gets a SID that the default API cannot see. A lookup returns 404 not found even though the console shows the trunk.
  • Regional endpoints such as api.dublin.ie1.twilio.com need regional API credentials. Your account SID and auth token get 401 Authenticate there.
  • The number’s Active Region and its trunk must be in the same region, and the console only shows you the configuration for the region you are viewing.
None of this changes what Unmute generates. It changes what you can inspect, and which console view tells you the truth, so note the region before you start comparing settings against a guide.

Then declare the names

Two files, and neither holds a value:
agent.yaml
Every name your connection maps belongs in secrets: too, which is what puts it in the generated .env.example and the startup check. The values go in .env locally, and in your platform’s secret store for a deployment.
A name you declare and never set is not caught at compile time. It is caught on the call, and the caller hears ringing that never ends. See the call rings and nobody answers.
Your build’s build/<target>/README.md is the authority for your own route: it was generated from your package, so it already names your region and your number.

Where to go next

LiveKit over Twilio

The sip route end to end: trunk, records, and what a rename breaks.

Pipecat over Twilio

The cloud-websocket route end to end.

connections/<name>.yaml

The file these values fill.

Transfers on LiveKit

Hand the caller to a person.