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

# Phone numbers

> Bring your own Twilio numbers and attach them to agents

Nixflex uses a **bring-your-own-Twilio (BYO)** model. You buy and own phone numbers in your Twilio account. Nixflex configures the webhooks on those numbers so calls route to the engine — but the numbers (and Twilio billing) stay with you.

## Why BYO Twilio

<Columns cols={2}>
  <Card title="You own the numbers" icon="lock">
    Numbers stay in your Twilio account. If you ever leave Nixflex, you keep them.
  </Card>

  <Card title="No platform markup" icon="dollar-sign">
    You pay Twilio's wholesale prices directly. Nixflex doesn't mark up call or SMS costs.
  </Card>

  <Card title="Multi-tenant ready" icon="users">
    One Nixflex agent can serve unlimited phone numbers — one per end-customer if you resell.
  </Card>

  <Card title="Skip A2P 10DLC blocks" icon="shield-check">
    For US SMS, your A2P registration applies. We don't get in the way.
  </Card>
</Columns>

## Importing a number

Import a Twilio number into an agent:

```bash theme={null}
curl -X POST https://api.nixflex.com/v1/phone-numbers \
  -H "Authorization: Bearer KEY_ID:KEY_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+447446466847",
    "twilio_sid": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "twilio_token": "your_twilio_auth_token",
    "agent_id": "agent_125207e452f8714a"
  }'
```

What this does, behind the scenes:

1. Validates the phone format and Twilio SID format
2. Verifies the number exists in **your** Twilio account using the credentials you sent
3. Confirms the agent belongs to your Nixflex account
4. Overwrites Twilio's webhooks on that number (voice, SMS, status callbacks) to point at Nixflex
5. Inserts a `phone_numbers` row linking number → agent → API key

After this, calls to that number land on the agent automatically.

<Warning>
  Importing a number **overwrites any existing webhooks** on that Twilio number. If you have other systems using the number, they will stop receiving calls.
</Warning>

## Multi-number, single-agent pattern

A single agent can be attached to many numbers. This is how reseller apps work:

```
agent_ringback_dental (one prompt, one personality)
  ├── +442011110001 → Smile Dental Croydon
  ├── +442011110002 → Pearly Whites Manchester
  ├── +442011110003 → Bright Bite Leeds
  └── +442011110004 → ... 200 more
```

Each number can carry its own `custom_prompt` (a business profile - see below), so the same agent template answers as a different business per number. On top of that, per-customer context also comes from:

* Which phone number was dialled (engine looks up the row)
* Any past call history for the caller's number (auto-fetched into the agent's prompt)

This pattern is how Ringback runs 200 dental clinics on one agent template.

## Per-number prompt (business profile)

Each `phone_numbers` row can hold a `custom_prompt` - a business profile for that specific number. It layers **on top of** the agent's prompt:

* **Agent prompt** = the shared template (how to behave - e.g. "a friendly receptionist"). Set by you, the developer.
* **Per-number prompt** = the specific business identity (name, address, hours, services) for that number. Different per end-customer.

When a call or SMS arrives, the engine appends the number's `custom_prompt` as a **BUSINESS PROFILE** section. If it conflicts with the general agent prompt, the number's details win. If a number has no `custom_prompt`, the agent prompt is used alone - so direct single-business agents are unaffected.

This applies to both **inbound calls** and **inbound SMS replies**, so a reseller's end-customer answers consistently across voice and text.

<Note>
  Set `custom_prompt` in the body when [importing a number](/api-reference/phone-numbers/import), or update it anytime with `PATCH /v1/phone-numbers/:phoneNumber` and body `{ "custom_prompt": "..." }` (send `null` or an empty string to clear it - the number then falls back to the agent prompt alone). Maximum 8000 characters. Outbound calls use the per-call `prompt` instead (see [Create outbound call](/api-reference/calls/create-outbound)).
</Note>

## Other per-number settings

The per-number model goes beyond the business profile. Several settings are configured **per phone number**, not per agent - so each number on a shared agent can behave differently:

| Setting                   | What it does per number                                                                             | Where                          |
| ------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------ |
| Voice                     | Each number can use its own voice (inbound and outbound). Falls back to the agent's voice if unset. | [Voices](/concepts/voices)     |
| Webhook                   | Each number can POST call data to its own endpoint.                                                 | [Webhooks](/advanced/webhooks) |
| Cal.com calendar          | Each number books into its own connected calendar.                                                  | [Cal.com](/actions/calcom)     |
| Business profile (prompt) | Each number's identity layered over the agent prompt (above).                                       | This page                      |

The engine resolves all of these from the number involved in the call - the dialled number for inbound, the `from_number` for outbound. A number with none of these set simply uses the agent's defaults. This is what lets one agent serve many end-customers, each with their own voice, calendar, and webhook.

## Listing numbers

```bash theme={null}
# All numbers
curl https://api.nixflex.com/v1/phone-numbers \
  -H "Authorization: Bearer KEY_ID:KEY_SECRET"

# Filter by agent
curl "https://api.nixflex.com/v1/phone-numbers?agent_id=agent_xxx" \
  -H "Authorization: Bearer KEY_ID:KEY_SECRET"
```

Returns numbers sorted by creation date, newest first.

## Removing a number

```bash theme={null}
curl -X DELETE https://api.nixflex.com/v1/phone-numbers/+447446466847 \
  -H "Authorization: Bearer KEY_ID:KEY_SECRET"
```

This clears Twilio's webhooks (so calls stop routing to Nixflex) and removes the row from our database.

<Note>
  Deleting a number from Nixflex does **not** release it from Twilio. The number stays in your Twilio account and continues to bill until you release it via Twilio's API or console. This is intentional — releasing is a permanent billing decision and stays with you.
</Note>

## Using multiple Twilio accounts

Each phone number stores its own Twilio Account SID and Auth Token. This means a single Nixflex account can serve numbers from **multiple Twilio accounts** — for example:

* A UK Twilio account for `+44` numbers
* A US Twilio account for `+1` numbers
* A separate Twilio subaccount per client (recommended for agencies)

When a call comes in or goes out, Nixflex automatically uses the right Twilio credentials based on the phone number involved. No configuration needed.

<Tip>
  **Best practice**: use a [Twilio Subaccount](https://www.twilio.com/docs/iam/api/subaccount) per client rather than your master account. This limits the blast radius if credentials are ever exposed and gives you per-client billing on Twilio.
</Tip>

## Constraints

* **One number, one agent.** A phone number can be attached to only one agent at a time. To move a number to a different agent, delete the existing record first then re-import.
* **Strict number matching.** Twilio's number search uses prefix matching; Nixflex performs a strict equality check after lookup to prevent accidental imports.
* **Account scope.** You can only see and manage numbers belonging to your API key. Cross-account access is blocked.

## Errors

See the [Import phone number API reference](/api-reference/phone-numbers/import) for the full list of error codes (`invalid_phone_format`, `agent_not_owned`, `number_already_imported`, etc.).
