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

# SIP trunks API overview

> Connect your own SIP carrier to Bolna with the /trunk API: create trunks, add gateways for outbound calls, carrier IPs for inbound calls, and numbers mapped to agents.

A **SIP trunk** connects your own SIP carrier to Bolna. Your carrier keeps your numbers and bills your minutes; Bolna's SIP edge receives your inbound calls and sends your agents' outbound calls to the carrier.

For a step-by-step setup, see the [SIP trunks overview](/docs/sip-trunking/overview) and [Connect your carrier](/docs/sip-trunking/connect-carrier) guides.

## Resource model

```
SIP trunk                 settings: channels, transport, codecs, carrier credentials
├── Gateways              carrier SIP hosts that outbound calls are sent to
├── Carrier IPs           carrier addresses that inbound calls are accepted from (ip_acls)
└── Numbers               your carrier's numbers, in E.164
    └── Agent             answers inbound calls to the number
```

* **Gateways** are only needed for outbound calls. They are tried in ascending `priority`, and a carrier failure that another gateway could fix moves on to the next one.
* **Carrier IPs** are only needed for inbound calls. Bolna's SIP edge refuses an INVITE from any address that is not on an active, inbound-enabled trunk's carrier IP list.
* **Numbers** carry the agent that answers inbound calls to them. A number without an agent is answered by the trunk's `default_inbound_agent_id`. The same number is the caller ID for outbound calls.

## Bolna's connection details

[`GET /trunk/pop`](/docs/api-reference/trunks/connection_details) returns the values you configure at your carrier: the SIP domain and port to send inbound calls to, the transports the edge accepts, the signalling IPs to allowlist, and the RTP port range. They are the same for every trunk.

## How calls use a trunk

**Inbound.** Your carrier sends the INVITE to Bolna's SIP domain. The edge accepts it only from one of your carrier IPs, matches the called number (the Request-URI user part) to a number's `e164` and then its `destination_key`, and answers with that number's agent. The INVITE must carry an SDP offer.

**Outbound.** Set the agent's telephony provider to `trunk` with the [Update agent API](/docs/api-reference/agent/v2/patch_update) (`"agent_config": {"telephony_provider": "trunk"}`), then call [`POST /call`](/docs/api-reference/calls/make) with one of your trunk numbers as `from_phone_number`. The trunk must be active, outbound-enabled and have at least one gateway. If the carrier challenges the call, Bolna answers with the trunk's `auth_username` and `auth_password`.

A trunk's `channels` caps its concurrent calls, inbound and outbound combined. An inbound call over the cap is refused with SIP `486 Busy Here`; an outbound call over it waits in your call queue until a channel is free.

## Endpoints

### Trunks

| Method | Endpoint | Description |
| - | - | - |
| `GET` | [`/trunk/trunks`](/docs/api-reference/trunks/list) | List your SIP trunks |
| `POST` | [`/trunk/trunks`](/docs/api-reference/trunks/create) | Create a SIP trunk |
| `GET` | [`/trunk/trunks/{trunk_id}`](/docs/api-reference/trunks/get) | Get a SIP trunk |
| `PATCH` | [`/trunk/trunks/{trunk_id}`](/docs/api-reference/trunks/update) | Update a trunk's settings |
| `DELETE` | [`/trunk/trunks/{trunk_id}`](/docs/api-reference/trunks/delete) | Delete a trunk with its gateways, carrier IPs and numbers |

### Gateways and carrier IPs

| Method | Endpoint | Description |
| - | - | - |
| `POST` | [`/trunk/trunks/{trunk_id}/gateways`](/docs/api-reference/trunks/add_gateway) | Add a gateway for outbound calls |
| `DELETE` | [`/trunk/trunks/{trunk_id}/gateways/{gateway_id}`](/docs/api-reference/trunks/remove_gateway) | Remove a gateway |
| `POST` | [`/trunk/trunks/{trunk_id}/ip-acls`](/docs/api-reference/trunks/add_carrier_ip) | Add a carrier IP for inbound calls |
| `DELETE` | [`/trunk/trunks/{trunk_id}/ip-acls/{acl_id}`](/docs/api-reference/trunks/remove_carrier_ip) | Remove a carrier IP |

### Numbers

| Method | Endpoint | Description |
| - | - | - |
| `POST` | [`/trunk/trunks/{trunk_id}/numbers`](/docs/api-reference/trunks/add_number) | Add a number to a trunk |
| `DELETE` | [`/trunk/trunks/{trunk_id}/numbers/{number_id}`](/docs/api-reference/trunks/remove_number) | Remove a number from a trunk |
| `PATCH` | [`/trunk/numbers/{number_id}`](/docs/api-reference/trunks/assign_agent) | Assign or clear the number's inbound agent |

### Calls and connection details

| Method | Endpoint | Description |
| - | - | - |
| `GET` | [`/trunk/trunks/{trunk_id}/calls`](/docs/api-reference/trunks/list_calls) | List recent calls on a trunk's numbers |
| `GET` | [`/trunk/pop`](/docs/api-reference/trunks/connection_details) | Get Bolna's SIP edge values for your carrier |

## Limits and formats

| Field | Rule |
| - | - |
| `name` | 1–100 characters |
| `description` | Up to 500 characters |
| `channels` | 1–1000, default `10` |
| `transport` | `udp` (default) or `tcp` |
| `codecs` | Comma-separated subset of `PCMU` and `PCMA`, default `PCMU,PCMA` |
| `auth_username`, `auth_password` | Set or cleared together; no quotes, `\|`, `{`, `}`, `\` or control characters |
| Gateways | Up to 8 per trunk. `host` is an IPv4 address or DNS name, `port` 1–65535 (default `5060`), `priority` 0–100 (default `0`, lowest tried first) |
| Carrier IPs | Up to 32 per trunk. Public IPv4 addresses or CIDR ranges no broader than `/16` |
| `e164` | E.164 with the plus, such as `+12025550143` |
| Numbers | A number can be live on only one trunk on Bolna at a time |

## Errors

Write endpoints return `200`, including the create endpoints. Error bodies take one of three shapes:

| Status | Body | When |
| - | - | - |
| `400` | `{"message": "..."}` | A value is refused, such as a private gateway address, a carrier IP broader than `/16`, or an agent that is not yours (`agent not in tenant`) |
| `403` | `{"message": "..."}` | The sub-account key's sub-account belongs to no organisation |
| `404` | `{"message": "..."}` | The trunk, gateway, carrier IP or number does not exist or is not yours; `message` names the ID |
| `409` | `{"detail": {"code": "...", "message": "..."}}` | `number_taken`, `gateway_conflict` or `convert_in_progress` |
| `422` | `{"detail": [{"loc": [...], "msg": "...", "type": "..."}]}` | The request failed validation, including any unknown field in the body |

Trunks belong to your organisation and are shared by its members. A sub-account API key reaches only the trunks created under that sub-account, and an agent assigned to a number must belong to the same organisation and sub-account.

<Note>
  The `/sip-trunks` endpoints are [Legacy SIP trunks (deprecated)](/docs/api-reference/sip-trunks/overview). Existing legacy trunks keep working; use the `/trunk` endpoints for every new setup, and see [Migrate to SIP trunks](/docs/migrating-to-sip-trunks/overview) to move an existing one.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.