> ## Documentation Index
> Fetch the complete documentation index at: https://unmute.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Unmute compiles to exactly three targets. Pipecat and LiveKit are code targets: compile writes a Python project you run. SLNG is a hosted target: compile writes a deployment body and SLNG runs the agent, so it has no `unmute dev`. Those three are the only values `provider` accepts in `targets.yaml`. Deepgram and ElevenLabs appear in these docs as model vendors, which is not the same thing as a target, and `slng` is both.
> The Go structs in `internal/spec` and `internal/ir` are the schema truth. Check a field against them, or run `unmute validate`, rather than against what you remember.

# Connection configuration

> One file, one phone route: the transport, the carrier, and the environment names that route needs.

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.

```yaml connections/twilio_sip.yaml theme={null}
transport: sip
carrier: twilio
environment:
  sip_address: SIP_TRUNK_HOSTNAME
  sip_username: SIP_AUTH_USERNAME
  sip_password: SIP_AUTH_PASSWORD
  from_number: SIP_FROM_NUMBER
```

## All keys

<ParamField path="transport" type="string" required>
  Mechanism that carries the call. Accepts `sip`, `connector`, `cloud-websocket`,
  `daily-sip`, as allowed by the target provider. Required; omission is refused.
</ParamField>

<ParamField path="carrier" type="string" required>
  Carrier account behind the route. Accepts `twilio`, `telnyx`, or `plivo`, as allowed by
  the route. Required; omission is refused.
</ParamField>

<ParamField path="environment" type="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.
</ParamField>

The target names the file and says nothing else about telephony:

```yaml targets.yaml theme={null}
targets:
  livekit:
    provider: livekit
    version: "1.8.1"
    sdk_language: python
    connection: twilio_sip
```

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.

```yaml connections/twilio_sip.yaml theme={null}
transport: sip
carrier: twilio
environment:
  sip_address: SIP_TRUNK_HOSTNAME
  sip_username: SIP_AUTH_USERNAME
  sip_password: SIP_AUTH_PASSWORD
  from_number: SIP_FROM_NUMBER
```

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.

```yaml connections/twilio_voice.yaml theme={null}
transport: cloud-websocket
carrier: twilio
```

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:

```text theme={null}
connections/twilio_voice.yaml: connection "twilio_voice" requires environment key
  "account_sid" for route (pipecat, cloud-websocket, twilio), because this package
  places or redirects calls. A package that only receives calls on this route needs
  no connection environment at all
```

## Which environment keys a route accepts

| Target  | `transport`       | `carrier`                   | `environment` keys                                                                               |
| ------- | ----------------- | --------------------------- | ------------------------------------------------------------------------------------------------ |
| Pipecat | `cloud-websocket` | `twilio`                    | `account_sid`, `auth_token`, `from_number`, and only when the package places or redirects a call |
| Pipecat | `daily-sip`       | `twilio`                    | `account_sid`, `auth_token`, `sip_address`, `from_number`                                        |
| LiveKit | `sip`             | `twilio`, `telnyx`, `plivo` | `sip_address`, `sip_username`, `sip_password`, `from_number`                                     |
| LiveKit | `connector`       | `twilio`                    | `account_sid`, `auth_token`, `from_number`                                                       |

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:

```text theme={null}
connections/twilio_sip.yaml:4: connection "twilio_sip" environment key "account_sid" is
  not accepted by route (livekit, sip, twilio); it accepts from_number, sip_address,
  sip_password, sip_username
```

## 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:

```yaml targets.yaml theme={null}
targets:
  pipecat:
    provider: pipecat
    version: "1.10.0"
    connection: twilio_websocket

  livekit:
    provider: livekit
    version: "1.8.1"
    sdk_language: python
    connection: twilio_connector
```

<CodeGroup>
  ```yaml Pipecat theme={null}
  # connections/twilio_websocket.yaml
  transport: cloud-websocket
  carrier: twilio
  environment:
    account_sid: TWILIO_ACCOUNT_SID
    auth_token: TWILIO_AUTH_TOKEN
    from_number: TWILIO_PHONE_NUMBER
  ```

  ```yaml LiveKit theme={null}
  # connections/twilio_connector.yaml
  transport: connector
  carrier: twilio
  environment:
    account_sid: TWILIO_ACCOUNT_SID
    auth_token: TWILIO_AUTH_TOKEN
    from_number: TWILIO_PHONE_NUMBER
  ```
</CodeGroup>

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:

```text theme={null}
connections/twilio_sip.yaml:1: kind is no longer written in a connection. Every transport
  in the catalog is telephony, so transport: sip already says it
```

**The numbers you dial** live in `agent.yaml` under
[`destinations:`](/reference/agent-yaml), 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:

```text theme={null}
connections/twilio_sip.yaml:21: transport "sip" with carrier "twilio" is not a route for
  provider pipecat. pipecat supports: cloud-websocket with twilio; daily-sip with twilio.
```

**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:

```text theme={null}
connections/twilio_sip.yaml:6: connection "twilio_sip" environment sip_password is not a
  valid environment variable name: use upper case letters, digits, and underscores, and
  do not start with a digit. This field takes a name and never a value. A deployment
  platform exports secrets through a shell, so a bad name would be missing at runtime
  with no error of its own
```

## 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:

```text wrap theme={null}
livekit: environment variables referenced but not declared in secrets: SIP_TRUNK_HOSTNAME (connections/twilio_sip.yaml environment sip_address)
```

**A connection nothing names is a warning, not an error.** The build succeeds and
tells you the file is dead:

```text theme={null}
Warnings:
  livekit: declares a route no target names, so nothing uses it: connections/twilio_voice.yaml
```

## Where to go next

<Columns cols={2}>
  <Card title="Variables" icon="braces" href="/reference/variables">
    Where a caller ID or a lookup result becomes a value the agent can use.
  </Card>

  <Card title="Phone calls" icon="phone" href="/telephony/overview">
    What each route means, and what the transport decides.
  </Card>
</Columns>
