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

# SIP trunking and BYOC

> Bring your own carrier and expose agents as SIP endpoints (advanced).

A trunk is the SIP connection that carries calls between Anyreach and a carrier. Most organizations use Anyreach-managed trunks and never touch this configuration. This page covers two advanced, API-only workflows: bringing your own carrier (BYOC) with a customer-owned trunk, and deploying an agent as a dialable SIP endpoint.

<Warning>
  These features are advanced and have no dashboard UI. Configure them through the API at `https://api.anyreach.ai`. Managed trunks are provisioned for you and cannot be edited or deleted through the API.
</Warning>

## Managed vs customer-owned trunks

Every trunk belongs to one organization. A trunk with a `managed_account_id` is provisioned and operated by Anyreach (for example a managed Twilio account) and is read-only over the API. A trunk with no `managed_account_id` is customer-owned: you control its inbound and outbound configuration. This is the BYOC path.

|                         | Managed trunk                        | Customer-owned (BYOC) trunk |
| ----------------------- | ------------------------------------ | --------------------------- |
| `managed_account_id`    | set                                  | `null`                      |
| Editable via API        | No (`PUT` and `DELETE` return `400`) | Yes                         |
| Inbound/outbound config | Managed by Anyreach                  | You set it                  |

<Note>
  When to use BYOC: choose a customer-owned trunk when you must route calls through your own carrier or PBX rather than an Anyreach-managed account. Otherwise use a managed trunk.
</Note>

## Trunk CRUD

All trunk endpoints live under `/core/trunks` and require the `trunks:read` or `trunks:manage` scope. Reads accept either scope; writes require `trunks:manage`.

| Method   | Path                | Scope                            | Notes                                                                                                                  |
| -------- | ------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `GET`    | `/core/trunks`      | `trunks:read` or `trunks:manage` | List trunks. Supports `name`, `created_after`, `created_before`, `updated_after`, `updated_before`, `limit`, `cursor`. |
| `GET`    | `/core/trunks/{id}` | `trunks:read` or `trunks:manage` | Get one trunk. `404` if not found.                                                                                     |
| `POST`   | `/core/trunks`      | `trunks:manage`                  | Create a customer-owned trunk.                                                                                         |
| `PUT`    | `/core/trunks/{id}` | `trunks:manage`                  | Update name and config. `400` if the trunk is managed.                                                                 |
| `DELETE` | `/core/trunks/{id}` | `trunks:manage`                  | Delete the trunk. `400` if the trunk is managed. Returns `204`.                                                        |

The create body takes a `name` and optional `inbound_config` and `outbound_config`. The organization is taken from your token, so you do not send `organization_id`.

```bash theme={null}
curl -X POST https://api.anyreach.ai/core/trunks \
  -H "Authorization: Bearer <token>" \
  -H "X-Anyreach-Org: <organization_id>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My carrier trunk",
    "inbound_config": {
      "enable_noise_cancellation": false,
      "media_encryption": "SIP_MEDIA_ENCRYPT_DISABLE",
      "allowed_addresses": ["203.0.113.10"]
    },
    "outbound_config": {
      "address": "sip.mycarrier.example.com",
      "auth_username": "anyreach",
      "auth_password": "<secret>",
      "transport": "SIP_TRANSPORT_UDP",
      "media_encryption": "SIP_MEDIA_ENCRYPT_DISABLE"
    }
  }'
```

<Note>
  The `X-Anyreach-Org` header is required only for user personal access tokens (`pat_`). Organization API keys (`ak_`) carry their organization implicitly.
</Note>

### Inbound config

`inbound_config` governs calls arriving from your carrier.

| Field                       | Type             | Default                     | Description                                                                                                          |
| --------------------------- | ---------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `enable_noise_cancellation` | boolean          | `false`                     | Apply noise cancellation to inbound audio.                                                                           |
| `media_encryption`          | enum             | `SIP_MEDIA_ENCRYPT_DISABLE` | Media encryption policy. See below.                                                                                  |
| `allowed_addresses`         | array of strings | `null`                      | Source addresses permitted to send calls. Empty strings are stripped; an empty list becomes `null` (no restriction). |

### Outbound config

`outbound_config` defines how Anyreach connects to your carrier to place calls. `address`, `auth_username`, and `auth_password` are required when you supply an outbound config.

| Field              | Type   | Default                     | Description                                      |
| ------------------ | ------ | --------------------------- | ------------------------------------------------ |
| `address`          | string | —                           | Carrier SIP host or domain. Required, non-empty. |
| `auth_username`    | string | —                           | SIP auth username. Required, non-empty.          |
| `auth_password`    | string | —                           | SIP auth password. Required, non-empty.          |
| `transport`        | enum   | `SIP_TRANSPORT_UDP`         | Transport protocol. See below.                   |
| `media_encryption` | enum   | `SIP_MEDIA_ENCRYPT_DISABLE` | Media encryption policy. See below.              |

### Enum values

| Enum               | Allowed values                                                                             |
| ------------------ | ------------------------------------------------------------------------------------------ |
| `media_encryption` | `SIP_MEDIA_ENCRYPT_DISABLE` (none), `SIP_MEDIA_ENCRYPT_ALLOW`, `SIP_MEDIA_ENCRYPT_REQUIRE` |
| `transport`        | `SIP_TRANSPORT_UDP`, `SIP_TRANSPORT_TCP`, `SIP_TRANSPORT_TLS`                              |

## Deploy an agent as a SIP endpoint

Instead of (or in addition to) attaching a phone number, you can expose a published agent as a dialable SIP URI. The agent then answers calls placed directly to its SIP address.

The URI has the form:

```text theme={null}
sip:<agent-uuid>@<host>
```

<Steps>
  <Step title="Publish the agent">
    The agent must have at least one published version. Deploying an agent with no published version returns `409`.
  </Step>

  <Step title="Deploy as SIP">
    Call `POST /core/agents/{id}/deploy-as-sip` with the `agents:manage` scope. The response returns the SIP URI and `deployed: true`. The operation is idempotent.

    ```bash theme={null}
    curl -X POST https://api.anyreach.ai/core/agents/<agent-id>/deploy-as-sip \
      -H "Authorization: Bearer <token>" \
      -H "X-Anyreach-Org: <organization_id>"
    ```

    ```json theme={null}
    {
      "uri": "sip:<agent-id>@<host>",
      "deployed": true
    }
    ```
  </Step>

  <Step title="Dial the endpoint">
    Route calls to the returned `uri` from your SIP infrastructure to reach the agent.
  </Step>

  <Step title="Undeploy when done">
    Call `DELETE /core/agents/{id}/deploy-as-sip` (scope `agents:manage`) to remove the endpoint. Returns `204` and is idempotent.
  </Step>
</Steps>

### SIP endpoint state on the agent

The agent `GET` response includes a `sip_endpoint` object reflecting current state, or `null` when state cannot be resolved.

| Field      | Type    | Description                                           |
| ---------- | ------- | ----------------------------------------------------- |
| `uri`      | string  | The agent's SIP URI.                                  |
| `deployed` | boolean | Whether the agent is currently reachable at that URI. |

### Errors

| Status | Cause                                                      |
| ------ | ---------------------------------------------------------- |
| `404`  | Agent not found.                                           |
| `409`  | Deploy attempted before the agent has a published version. |

## Related

<CardGroup cols={2}>
  <Card title="Telephony overview" icon="phone" href="/telephony/overview">
    How phone numbers, trunks, and agents fit together.
  </Card>

  <Card title="Telephony API reference" icon="code" href="/api-reference/telephony/overview">
    Full endpoint reference for telephony resources.
  </Card>
</CardGroup>
