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

# Set up an inbound phone agent via SIP

> Point a Twilio number you already own at AssemblyAI over a SIP trunk and attach a voice agent. Inbound only.

Twilio passes inbound calls to AssemblyAI over SIP, so there's no media server, audio bridge, or webhook to run.

```
Caller → your Twilio number → SIP trunk → AssemblyAI → your agent
```

**You need:**

* A [Twilio account](https://console.twilio.com) (Account SID + Auth Token from the Console home page) with a phone number you already own
* An [AssemblyAI API key](https://www.assemblyai.com/dashboard/api-keys)
* An `agent_id`. Don't have one? [Create an agent](/docs/voice-agents/voice-agent-api/create-agent) first.
* The [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart) installed and logged in (`twilio login`), plus `curl`, `jq`, and `uuidgen`

Prefer clicking? You can do every Twilio step in the [Console](https://console.twilio.com) under **Voice → Manage → Elastic SIP Trunking**. The CLI just makes it scriptable.

Five steps, three on Twilio and two on AssemblyAI:

1. Create a SIP trunk
2. Route its origination to `sip:sip.assemblyai.com`
3. Attach your number to the trunk
4. Register the number with AssemblyAI
5. Bind your agent to it

## 1. Set your details

Save these in a `.env` file in your working directory:

```bash .env icon=gear theme={null}
AAI_API_KEY="your-assemblyai-api-key"
AGENT_ID="7ad24396-b822-4dca-871a-be9cc4781cf9"    # the agent that answers
NUMBER="+1..."                                     # your Twilio number, E.164
TRUNK_DOMAIN="my-company-agent.pstn.twilio.com"    # you invent this
```

Load it into your shell:

```bash theme={null}
set -a && source .env && set +a
```

`TRUNK_DOMAIN` doesn't exist yet. You're naming the trunk you create in the next step, and it must end in `.pstn.twilio.com` and be unique across Twilio, so include your company name.

## 2. Point Twilio at AssemblyAI

Creates the trunk, points its origination at `sip:sip.assemblyai.com`, and attaches your number to the trunk.

```bash setup-trunk.sh icon=terminal expandable theme={null}
#!/usr/bin/env bash
set -euo pipefail

# 1. Create the trunk
TRUNK_SID=$(twilio api:trunking:v1:trunks:create \
  --friendly-name "AssemblyAI voice agent" \
  --domain-name "$TRUNK_DOMAIN" -o json | jq -r '.[0].sid')
echo "Trunk: $TRUNK_SID"

# 2. Route incoming calls to AssemblyAI
twilio api:trunking:v1:trunks:origination-urls:create \
  --trunk-sid "$TRUNK_SID" --friendly-name "AssemblyAI SIP" \
  --sip-url "sip:sip.assemblyai.com" --priority 1 --weight 1 --enabled >/dev/null

# 3. Attach your number to the trunk
NUMBER_SID=$(twilio api:core:incoming-phone-numbers:list \
  --phone-number "$NUMBER" -o json | jq -r '.[0].sid')
twilio api:trunking:v1:trunks:phone-numbers:create \
  --trunk-sid "$TRUNK_SID" --phone-number-sid "$NUMBER_SID" >/dev/null
echo "Number $NUMBER attached to trunk"
```

The trunk now controls the number. Any Voice webhook set on the number itself no longer applies.

Reusing a trunk that already has an origination URL? Delete the old one before running this, or calls may go to the wrong place:

```bash theme={null}
twilio api:trunking:v1:trunks:origination-urls:list --trunk-sid "$TRUNK_SID"
twilio api:trunking:v1:trunks:origination-urls:remove --trunk-sid "$TRUNK_SID" --sid "OUxxxx"
```

## 3. Attach your agent to the number

Registers the number with AssemblyAI against your trunk, binds `AGENT_ID` to it, and prints the result.

```bash register-number.sh icon=phone-arrow-down-left expandable theme={null}
#!/usr/bin/env bash
set -euo pipefail

AAI="https://agents.us.assemblyai.com/v1"
AUTH=(-H "Authorization: Bearer $AAI_API_KEY" -H "Content-Type: application/json")

# 4. Register the number
curl -fsS -X POST "$AAI/phone-numbers/import" "${AUTH[@]}" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d "{\"phone_number\":\"$NUMBER\",\"termination_uri\":\"$TRUNK_DOMAIN\"}" >/dev/null

# 5. Bind the agent
curl -fsS -X PUT "$AAI/phone-numbers/$NUMBER/agent" "${AUTH[@]}" \
  -d "{\"agent_id\":\"$AGENT_ID\"}" >/dev/null

# Verify
curl -fsS "$AAI/phone-numbers/$NUMBER" "${AUTH[@]}" | jq
```

The final `jq` output should show your `agent_id` with `"type": "imported"`.

<Tip>
  To point the number at a different agent later, re-run only the `PUT`. Twilio needs no changes, and editing the agent itself changes nothing here: the number is bound to the ID, so updates to that agent take effect on the next call.
</Tip>

## 4. Call it

Ring the number. You should hear the greeting, then have a real-time conversation with the agent.

<Note>
  Twilio bills the inbound minutes and AssemblyAI bills the session, so a live number draws on both accounts.
</Note>

## If it does not work

| Symptom                               | Cause                                                                                                                                                                                                                  |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Nothing happens when you call         | The number isn't on the trunk, the origination URL isn't exactly `sip:sip.assemblyai.com` and enabled, or no agent is attached. A number with a Voice webhook still set in the Console is not going through the trunk. |
| Call connects, then silence           | The origination URL is wrong or disabled.                                                                                                                                                                              |
| `is attached to a different trunk`    | Detach it in the Twilio Console, then re-run.                                                                                                                                                                          |
| `Twilio POST /v1/Trunks failed (400)` | The SIP domain is taken or malformed. Choose another `*.pstn.twilio.com`.                                                                                                                                              |
| `404 agent_not_found`                 | Wrong `AGENT_ID`.                                                                                                                                                                                                      |
| `409` number already registered       | Already imported. Safe to ignore on a re-run.                                                                                                                                                                          |
| `422 phone_number_has_no_agent`       | Re-run the `PUT` in step 3.                                                                                                                                                                                            |
| Twilio command not recognised         | Names change between CLI versions. Run `twilio api:trunking:v1 --help`, or use the Console.                                                                                                                            |

## Want it scripted?

The [Python](https://github.com/AssemblyAI/voice-agent-starter-python) and [JavaScript](https://github.com/AssemblyAI/voice-agent-starter-js) starters run all five steps as one idempotent command, publishing the agent along the way:

<CodeGroup>
  ```bash Python theme={null}
  python deployment/telephony/connect.py
  ```

  ```bash JavaScript theme={null}
  npm run phone
  ```
</CodeGroup>

## Next steps

* [Configure your agent](/docs/voice-agents/voice-agent-api/session-configuration): Customize the system prompt, greeting, and turn detection.
* [Choose a voice](/docs/voice-agents/voice-agent-api/voices): Pick a voice for your agent.
* [Add tools to your agent](/docs/voice-agents/voice-agent-api/tools/overview): Give your agent the ability to call functions.
