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

# SIP trunking

> Create and manage SIP trunks, origination URIs, credentials and IP access control lists, route a number to a trunk, and inspect trunk calls.

Manage Session Initiation Protocol (SIP) [trunks](https://plivo.com/docs/voice-agents/sip-trunking/overview.md), which carry calls between Plivo and your phone system or voice-agent platform, and the calls that went over them. `plivo sip-trunking` is the same command as `plivo sip`. After [logging in](https://plivo.com/docs/cli/install.md#log-in-with-a-browser), list your trunks:

```bash theme={null}
plivo sip trunks list
```

A working setup has four parts. To connect LiveKit, ElevenLabs, Retell or Vapi step by step, see [Connect a SIP voice-agent platform](https://plivo.com/docs/cli/voice-agent/connect-sip-platform.md).

| Part | What it is | Command |
| - | - | - |
| Origination URI | Where Plivo sends inbound calls, such as your voice-agent platform's SIP host | `plivo sip uris create` |
| Credential or IP access control list | How Plivo knows an outbound call really comes from your platform | `plivo sip credentials create` or `plivo sip ip-acl create` |
| Trunk | An inbound trunk points at a URI; an outbound trunk uses a credential or an IP list | `plivo sip trunks create` |
| Number | Routed to the inbound trunk | `plivo numbers update <number> --trunk-id <trunk_id>` |

> [!NOTE]
>
> SIP endpoints (registered devices and usernames) are a different product, under `plivo voice endpoints` on the [Voice](https://plivo.com/docs/cli/apis/voice.md) page.

Command syntax: replace `<values>` and omit `[flags]` unless adding options. Repeat a flag marked `repeatable` for each value. Global flags, and the paging flags `--all`, `--limit` and `--offset` on every list: see [Configuration](https://plivo.com/docs/cli/configure.md).

## Safety rules

* `--dry-run` previews changes. Dependency checks can still read account resources; no change is applied.
* Passwords are read from stdin only (`--password-stdin`); there is no `--password` flag, and the CLI never prints the password back. Supply stdin from a secret manager or a variable populated without shell history, and avoid shell tracing.
* Values are checked before any request. A `--uri` with a space, a bad port, an unknown transport, a malformed host or a password in it (`user:password@host`) is refused, and so is an `--ip` that is not one address or CIDR range. Repeat `--ip` for more than one; a comma-separated list is refused.
* Plivo accepts IPv4 only, so an IPv6 address in a URI or an IP access control list is refused.
* Plivo can never reach a private, loopback, link-local, carrier-grade NAT, benchmarking, multicast or reserved address. Such an address is refused as a URI host and in `sip ip-acl create` and `update`. A range that allows the whole internet is only warned about.
* A trunk ID must be digits. A SIP call ID, and a URI, credential or IP access control list ID, must be a UUID. Any other value is refused before any request.
* `create` needs `--name` on URIs, trunks and IP access control lists.
* A delete needs `--yes`, and first reads everything that depends on the object: every number routed to a trunk, every trunk using a URI, credential or IP list. If something depends on it, the delete is refused with exit code `5` unless you add `--force` to `--yes`. If the check can't read every page, the delete is refused.
* `--dry-run` alone previews a delete. For an object something depends on, `--dry-run` lists the dependents and exits `5`; `--dry-run --force` previews the delete.

Every `delete` below takes `--force`: delete even though something depends on it (with `--yes`).

> [!WARNING]
>
> Deleting a URI that is a trunk's primary URI also deletes that trunk. Deleting a URI that is a trunk's fallback URI only clears the fallback; the trunk stays. Deleting a trunk detaches every number routed to it, so inbound calls to those numbers stop.

## Trunks

An inbound trunk needs a primary URI. An outbound trunk needs a credential or an IP access control list. After `create`, the CLI reads the trunk back and prints its `trunk_domain`: paste that into your platform for outbound calls.

`--secure` turns on Transport Layer Security (TLS) for signaling and Secure Real-time Transport Protocol (SRTP) for audio. Secure trunking is billed per minute.

`sip trunks update` flags take an explicit value so they can be reversed, for example `--secure=false` or `--status disabled`. It keeps an inbound trunk's fallback URI when you change something else; pass `--fallback-uri ""` to remove it. Flags that don't fit the trunk's direction, such as `--fallback-uri` on an outbound trunk, and a `--status` other than `enabled` or `disabled`, are refused before any request.

| Command | What it does |
| - | - |
| `plivo sip trunks create [flags]` | Create a trunk |
| `plivo sip trunks delete <trunk_id> [flags]` | Delete a trunk (requires --yes) |
| `plivo sip trunks get <trunk_id>` | Get one trunk by ID |
| `plivo sip trunks list [flags]` | List trunks. `--direction inbound\|outbound` filters |
| `plivo sip trunks update <trunk_id> [flags]` | Update a trunk |

> [accordion] plivo sip trunks create
>
> | Flag | Description |
> | - | - |
> | `--credential <value>` | credential uuid (outbound) |
> | `--direction <value>` | inbound\|outbound (required) |
> | `--fallback-uri <value>` | fallback origination URI uuid |
> | `--ip-acl <value>` | IP access control list uuid (outbound) |
> | `--name <value>` | trunk name (required) |
> | `--platform <value>` | check against a platform's guide: livekit\|elevenlabs\|retell\|vapi |
> | `--secure` | enable TLS/SRTP |
> | `--uri <value>` | primary origination URI uuid (inbound) |
>
> ```bash theme={null}
> plivo sip trunks create --name my-trunk --direction inbound --uri "<uri_uuid>"
> plivo sip trunks create --name agent-out --direction outbound --platform livekit --credential "<uuid>" --secure
> ```

> [accordion] plivo sip trunks update
>
> | Flag | Description |
> | - | - |
> | `--credential <value>` | credential uuid |
> | `--direction <value>` | inbound\|outbound (read from the trunk when omitted) |
> | `--fallback-uri <value>` | fallback origination URI uuid ("" removes it) |
> | `--ip-acl <value>` | IP access control list uuid |
> | `--name <value>` | trunk name |
> | `--secure` | enable TLS/SRTP (takes a value: --secure=false) |
> | `--status <value>` | enabled\|disabled |
> | `--uri <value>` | primary origination URI uuid |

## Origination URIs

Give `--uri` as `host[:port][;transport=tcp|tls]`, for example `sip.example.com:5060;transport=tcp`. With no transport, the URI uses UDP. Quote a URI that contains `;`, or the shell cuts the command there. `--transport` adds `;transport=` for you.

A `sip:` or `sips:` prefix is rewritten to the host form, because the API refuses both schemes. `sip:` is dropped. `sips:` becomes `;transport=tls`, on port 5061 when you give no port; `sips:` with another transport is refused. The CLI prints the URI it sent on stderr:

```text theme={null}
--uri is rewritten to sip.example.com:5061;transport=tls: the API refuses the sips: scheme.
```

A URI with a user part, such as `sip:user@host`, is refused; give the host alone. A URI never holds a password: when the platform needs authentication, pass `--authentication-needed`, `--username` and the password on stdin with `--password-stdin`.

| Command | What it does |
| - | - |
| `plivo sip uris create [flags]` | Create an origination URI |
| `plivo sip uris delete <uri_uuid> [flags]` | Delete an origination URI (requires --yes) |
| `plivo sip uris get <uri_uuid>` | Get one origination URI |
| `plivo sip uris list [flags]` | List origination URIs |
| `plivo sip uris update <uri_uuid> [flags]` | Update an origination URI |

After a URI delete, each trunk that used the URI is read back. The result says which trunks were deleted with it and which are still there. With `-o json` they are in `trunks_deleted` and `trunks_kept`, and any that could not be read are in `trunks_unchecked`.

> [accordion] plivo sip uris create and update
>
> | Flag | Description |
> | - | - |
> | `--authentication-needed` | require authentication (takes a value on `update`) |
> | `--name <value>` | URI name (required on `create`) |
> | `--password-stdin` | read the URI password from stdin |
> | `--platform <value>` | `create` only: fill in a platform's published values: livekit\|elevenlabs\|retell\|vapi |
> | `--transport <value>` | `create` only: udp\|tcp\|tls, added to --uri as ;transport= |
> | `--uri <value>` | host, host:port, host;transport=…, or sip:host |
> | `--username <value>` | username when authentication is needed |
>
> ```bash theme={null}
> plivo sip uris create --name eleven --uri "sip.rtc.elevenlabs.io:5060;transport=tcp"
> plivo sip uris create --name eleven --platform elevenlabs
> plivo sip uris create --name agent --platform livekit --uri "<project>.sip.livekit.cloud"
> ```

## Credentials

Pass the password on stdin; the CLI does not generate one. Plivo's rules are checked before any request: the username is 5 to 20 letters and digits, and the password is 5 to 20 characters with at least one of `~!@#$%^&*()_+`.

```bash theme={null}
printf '%s' "$SIP_PASSWORD" | plivo sip credentials create --name c1 --username sipuser1 --password-stdin
```

| Command | What it does |
| - | - |
| `plivo sip credentials create [flags]` | Create a credential |
| `plivo sip credentials delete <credential_uuid> [flags]` | Delete a credential (requires --yes) |
| `plivo sip credentials get <credential_uuid>` | Get one credential |
| `plivo sip credentials list [flags]` | List credentials |
| `plivo sip credentials update <credential_uuid> [flags]` | Update a credential |

Flags on `create` and `update`: `--name <value>` (credential name), `--username <value>` (SIP username, required on `create`) and `--password-stdin` (required on both: every update rewrites the password).

## IP access control lists

An IP access control list (ACL) allows calls from specified addresses. `--ip` takes IPv4 addresses or Classless Inter-Domain Routing (CIDR) ranges (repeatable). On `update` it replaces the whole list, so pass every address you want to keep.

```bash theme={null}
plivo sip ip-acl create --name platform --ip "<platform_ip>" --ip "<platform_cidr>"
plivo sip ip-acl create --name vapi --platform vapi
```

| Command | What it does |
| - | - |
| `plivo sip ip-acl create [flags]` | Create an IP access control list. Flags: `--name` (required), `--ip`, `--platform vapi` (fills `--ip` with the platform's published addresses) |
| `plivo sip ip-acl delete <ipacl_uuid> [flags]` | Delete an IP access control list (requires --yes) |
| `plivo sip ip-acl get <ipacl_uuid>` | Get one IP access control list by UUID |
| `plivo sip ip-acl list [flags]` | List IP access control lists |
| `plivo sip ip-acl update <ipacl_uuid> [flags]` | Update an IP access control list. Flags: `--name`, `--ip` (replaces the list) |

## Route a number to a trunk

`plivo numbers update --trunk-id` routes a number to an inbound trunk, taking it off the application it was attached to. It warns when the trunk is disabled, and refuses an outbound trunk. For an India (+91) number the CLI checks its compliance application first, and refuses a number without accepted know your customer (KYC) compliance; see [Numbers](https://plivo.com/docs/cli/apis/numbers.md#compliance-when-you-buy-or-route-a-number).

```bash theme={null}
plivo numbers update 14155551234 --trunk-id "<trunk_id>" --dry-run
plivo numbers update 14155551234 --trunk-id "<trunk_id>"
```

## Trunk calls

| Command | What it does |
| - | - |
| `plivo sip calls diagnose <call_uuid>` | Diagnose what happened on a SIP Trunking call (AI-powered) |
| `plivo sip calls get <call_uuid>` | Get one SIP Trunking call by UUID |
| `plivo sip calls insights <call_uuid>` | Show the call quality Plivo measured on a SIP Trunking call |
| `plivo sip calls list [flags]` | List SIP Trunking calls |

* `get` and `insights` end with which side hung up: Plivo's hangup cause, code and source. The platform's final SIP response shows as "not available", because no API returns it; the console's SIP logs have it.
* `insights` shows round-trip time, jitter, packet loss, post-dial delay and the Plivo quality score, with the carrier and region of each leg, as the API returns them.
* `diagnose` asks Plivo's AI assistant to explain the call. It reads trunk calls only; for a Voice API call use `plivo voice calls diagnose`. See [Diagnose a call](https://plivo.com/docs/cli/voice-agent/diagnose-call.md) for the JSON result and exit codes.

```bash theme={null}
plivo sip calls diagnose 8f3c1a2e-0d44-4a6f-9c31-2b7e5a90d1f7
plivo sip calls list --direction outbound --since 2026-09-01
plivo sip calls list --hangup-source carrier -o json
```

> [accordion] plivo sip calls list
>
> Without `--until`, the search runs to now. `--until` needs `--since` and must come after it. A malformed `--from-number` or `--to-number` is refused before any request.
>
> | Flag | Description |
> | - | - |
> | `--direction <value>` | inbound\|outbound |
> | `--from-number <value>` | filter by caller ID |
> | `--hangup-cause-code <integer>` | filter by numeric hangup cause code |
> | `--hangup-source <value>` | who ended the call: customer\|carrier\|zentrunk |
> | `--since <value>` | calls ending at or after this UTC time (YYYY-MM-DD\[ HH:MM\[:SS]]). Same as `--from-date` |
> | `--stir-verification <value>` | "Verified"\|"Not Verified"\|"Not Applicable" |
> | `--to-number <value>` | filter by destination |
> | `--until <value>` | calls ending at or before this UTC time (YYYY-MM-DD\[ HH:MM\[:SS]]); defaults to now when --since is given. Same as `--to-date` |

## Test a SIP URI

`plivo sip test --uri <value>` checks from your machine that a SIP host answers, before you send calls to it. It needs no login and never sends an INVITE, so no call is placed. `--uri` (required) is the SIP URI to test, e.g. "sip.example.com;transport=tcp".

When you give a host without a port and it publishes a SIP SRV record, the test warns and names the record's target, with the `--uri` to test it. It still tests the host you gave. See [Check that the platform answers](https://plivo.com/docs/cli/voice-agent/connect-sip-platform.md#check-that-the-platform-answers).

```bash theme={null}
plivo sip test --uri "agent.example.com:5061;transport=tls"
plivo sip test --uri "sip.example.com:5060;transport=tcp" -o json
```
