Skip to main content
A connection is one whole phone route. It says how the call is carried, which carrier hands it over, and which environment variables hold that account’s credentials.
connections/twilio_sip.yaml

All keys

string
required
Mechanism that carries the call. Accepts sip, connector, cloud-websocket, daily-sip, as allowed by the target provider. Required; omission is refused.
string
required
Carrier account behind the route. Accepts twilio, telnyx, or plivo, as allowed by the route. Required; omission is refused.
map of strings
Names holding the route’s account values. Accepts route keys listed below to UPPER_SNAKE env names. Omission is allowed only when the route needs no account values, such as receive-only Pipecat cloud-websocket. Otherwise the missing route keys are refused.
The target names the file and says nothing else about telephony:
targets.yaml
So when you want to know how a call reaches this agent, you open one file. The file stem is the connection name. It must be lower snake case and cannot start with an underscore, for example twilio_sip.yaml. The setting names on the left of environment are fixed by the route. The names on the right are yours, and they are names only. The compiler never reads the values, so a package with connections still validates and compiles with no credentials present anywhere.

The two shapes

Full route

A route with credentials. Most connections look like this.
connections/twilio_sip.yaml
From examples/salon-concierge, where it is the LiveKit target’s route.

No credentials

Receive only on Pipecat’s cloud-websocket route. Pipecat Cloud terminates the carrier’s media stream itself, so a package that only answers calls needs nothing from your Twilio account.
connections/twilio_voice.yaml
The moment the package places a call, or hands one to a person, the same route needs account_sid, auth_token, and from_number, because both of those speak to Twilio’s API in your name. The refusal says which behavior asked for them:

Which environment keys a route accepts

The SIP route uses standard SIP names rather than one vendor’s, because the same generated code dials through any SIP carrier with them. Telnyx and Plivo reach a package through LiveKit’s sip route, with those same SIP names. No route takes a carrier’s own API key. A key from another route is refused, and the refusal carries the accepted set so you do not have to go looking for it:

One target, one connection

A target names at most one connection, and a connection declares one transport. So two targets on different transports need two files, even when there is one carrier account behind both:
targets.yaml
Same three names, different mechanism. The file name does not have to repeat the transport, but its stem must still be lower snake case.

What does not go in a connection

kind: is not written. Every transport in the catalog is telephony, so the first line already said it:
The numbers you dial live in agent.yaml under destinations:, not here. A destination is who this agent escalates to, which is the same desk whichever carrier reaches it. A route the target’s provider does not have is refused with the routes it does have:
A value that is not an UPPER_SNAKE shell identifier, because a deployment platform exports secrets through a shell and this failure would otherwise be silent. The error names the setting key, not the value, because the value slot may contain a pasted credential:

Two more rules worth knowing

Every name you write here belongs in secrets: too. A missing declaration is a warning. The compiler still knows the route requires the name and keeps it in the generated environment instructions and call-time checks; declaring it makes the package’s explicit secret inventory agree with that inferred requirement:
A connection nothing names is a warning, not an error. The build succeeds and tells you the file is dead:

Where to go next

Variables

Where a caller ID or a lookup result becomes a value the agent can use.

Phone calls

What each route means, and what the transport decides.