---
title: "Numbers"
description: "Give an agent a phone number, attach one you already own, move it between agents, and release it."
canonical_url: "https://www.agent-identity.dev/docs/phone/numbers"
markdown_url: "https://www.agent-identity.dev/docs/phone/numbers.md"
last_updated: "2026-10-09"
x_farming_labs_generated_preamble: true
agent:
  tokenBudget: 800
  task: "Give an agent a phone number, or move or release one."
  outcome: "POST /v1/phone/numbers returns 201 with the number, and the agent answers calls with Aid Voice unless another action was given."
  appliesTo:
    package:
      - "@aid/api"
      - "@agentidentity/sdk"
  prerequisites:
    - "An org key. Agent keys can read their own number but cannot buy, move or release one."
    - "A verified owner. Buying a number spends money."
  files:
    - "apps/api/src/services/phone.ts"
  commands:
    - run: "curl -sS -X POST https://api.agent-identity.dev/v1/phone/numbers -H \"authorization: Bearer $AID_ORG_KEY\" -H 'content-type: application/json' -d '{\"identity_id\":\"<agent-id>\",\"state\":\"NY\"}'"
      description: "Buy a number in New York for an agent."
  sideEffects:
    - "A new number is bought from the carrier and costs money. Attaching a number already in the carrier account buys nothing."
    - "Counts against the plan's number limit."
  verification:
    - description: "List the organization's numbers."
      expect: "GET /v1/phone/numbers includes the number with identity_id set to the agent and status active."
  rollback:
    - "DELETE /v1/phone/numbers/{id} gives the number back to the carrier. It cannot be undone."
  failureModes:
    - symptom: "409 phone.conflict: this agent already has a phone number."
      resolution: "An agent holds one number. Release or move the existing one first."
    - symptom: "429 phone.limit_exceeded on provisioning."
      resolution: "The organization holds as many numbers as its plan allows. Release one or upgrade."
    - symptom: "502 phone.provider_unavailable: no number is available there right now."
      resolution: "Try another state, or buy one in the carrier's portal and attach it with number."
    - symptom: "400: that number is not in the carrier account."
      resolution: "number only attaches numbers this server's carrier account already owns. Leave it out to buy a new one."
---

# Numbers
URL: /docs/phone/numbers
LLM index: /llms.txt
Description: Give an agent a phone number, attach one you already own, move it between agents, and release it.
Related: /docs/phone/incoming-calls, /docs/phone/limits, /docs/getting-started/authentication

<!-- farming-labs:agent-contract:start -->
## Agent Contract

Task: Give an agent a phone number, or move or release one.
Outcome: POST /v1/phone/numbers returns 201 with the number, and the agent answers calls with Aid Voice unless another action was given.

### Applies To

- Package: `@aid/api`, `@agentidentity/sdk`

### Prerequisites

- An org key. Agent keys can read their own number but cannot buy, move or release one.
- A verified owner. Buying a number spends money.

### Files

- `apps/api/src/services/phone.ts`

### Commands

- `curl -sS -X POST https://api.agent-identity.dev/v1/phone/numbers -H "authorization: Bearer $AID_ORG_KEY" -H 'content-type: application/json' -d '{"identity_id":"<agent-id>","state":"NY"}'` — Buy a number in New York for an agent.

### Side Effects

- A new number is bought from the carrier and costs money. Attaching a number already in the carrier account buys nothing.
- Counts against the plan's number limit.

### Verification

- List the organization's numbers.
  - Expected: GET /v1/phone/numbers includes the number with identity_id set to the agent and status active.

### Rollback

- DELETE /v1/phone/numbers/{id} gives the number back to the carrier. It cannot be undone.

### Failure Modes

- 409 phone.conflict: this agent already has a phone number. — Recovery: An agent holds one number. Release or move the existing one first.
- 429 phone.limit_exceeded on provisioning. — Recovery: The organization holds as many numbers as its plan allows. Release one or upgrade.
- 502 phone.provider_unavailable: no number is available there right now. — Recovery: Try another state, or buy one in the carrier's portal and attach it with number.
- 400: that number is not in the carrier account. — Recovery: number only attaches numbers this server's carrier account already owns. Leave it out to buy a new one.
<!-- farming-labs:agent-contract:end -->

# Numbers

An agent can hold one phone number. Buying, moving and releasing numbers needs an **org key** and a verified owner,
because it spends money.

## Get a number

```ts title="number.ts"
import { AgentClient } from "@agentidentity/sdk";

const org = new AgentClient({ baseUrl: "https://api.agent-identity.dev", apiKey: process.env.AID_ORG_KEY! });

const number = await org.phone.provisionNumber({ identityId: agent.id, state: "NY" });
console.log(number.number); // +1212…
```

```bash title="terminal"
curl -sS -X POST https://api.agent-identity.dev/v1/phone/numbers \
  -H "authorization: Bearer $AID_ORG_KEY" -H 'content-type: application/json' \
  -d '{"identity_id":"'$AID_AGENT'","state":"NY"}'
```

`state` is a two-letter US state and is optional. The new number answers with [Aid Voice](/docs/phone/aid-voice)
straight away. To start with a different setting, pass `incoming_call_action` (with `client_websocket_url` or
`incoming_call_webhook_url` when it needs one). See [Incoming calls](/docs/phone/incoming-calls).

## Attach a number you already own

If the number is already in the carrier account, pass it as `number`. It is attached to the agent and nothing is bought.

```ts title="existing.ts"
await org.phone.provisionNumber({ identityId: agent.id, number: "+14155550100" });
```

`GET /v1/phone/carrier-numbers` (`listCarrierNumbers()`) lists numbers in the carrier account that no agent has yet.
`ready: false` means the number is not connected to this server's voice application, so it will not deliver calls here.

## Read numbers

| Request | SDK | Returns |
| --- | --- | --- |
| `GET /v1/phone/numbers` | `listNumbers()` | Every number in the organization. An agent key sees only its own. |
| `GET /v1/phone/numbers/{id}` | `getNumber(id)` | One number. |

A number has `id`, `identity_id`, `number` (E.164), `provider`, `status` and `created_at`.

## Move or detach a number

```ts title="move.ts"
await org.phone.assignNumber(number.id, otherAgent.id); // move it
await org.phone.assignNumber(number.id, null);          // detach it, keeping the number
```

`PATCH /v1/phone/numbers/{id}` with `{"identity_id": "…"}` or `null`. Moving fails with 409 if the other agent already
has a number.

## Release a number

```ts title="release.ts"
await org.phone.releaseNumber(number.id);
```

`DELETE /v1/phone/numbers/{id}` gives the number back to the carrier. This cannot be undone.

## How many numbers

| Plan | Numbers |
| --- | --- |
| Free | 2 (set by the server) |
| Builder | 3 |
| Team | 20 |
| Enterprise | No fixed limit |

See [Limits](/docs/phone/limits) for calls and minutes.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
Docs-scoped sitemap: [/docs/sitemap.md](/docs/sitemap.md).
Well-known sitemap: [/.well-known/sitemap.md](/.well-known/sitemap.md).
