# Buy a number over the API (/docs/buy-a-number-api)

> Search the OmniDimension number shop, buy a number, and release it when you are done.

Everything the [OmniDimension number shop](/docs/dashboard-guides/numbers-shop) does in the
dashboard, you can do from your own code: search what is available in a region, buy a number,
list what you hold, and release one you no longer need.

## Search what is available [#search-what-is-available]

```http
GET /api/v1/phone_number/search?region=IN
```

Narrow the results with `pattern`, and page through with `page` and `limit`.

```json
{
  "success": true,
  "region": "IN",
  "numbers": [
    {
      "phone_number": "+911155590077",
      "monthly_rental_usd": 5.0,
      "validity_days": 30,
      "region": "IN",
      "kyc_required": true
    }
  ],
  "total": 42,
  "page": 1,
  "limit": 20,
  "total_pages": 3
}
```

Price and validity are flat per region, so every result carries the same
`monthly_rental_usd`, and that is the exact amount the purchase will charge.

Searching does not reserve anything. A number is claimed only when a purchase starts, so a
number you saw a moment ago can be gone by the time you buy it.

## Buy one [#buy-one]

```http
POST /api/v1/phone_number/purchase
Idempotency-Key: <a fresh UUID>

{ "region": "IN", "phone_number": "+911155590077" }
```

The rental comes out of your wallet and the number is added to your account, ready to attach
to an agent.

  It is how you recover a lost response. If your request times out, retry with the **same** key
  and you get your original order back with `replayed: true`, instead of guessing whether the
  first attempt went through. Use a fresh key for each new purchase: reusing an old one returns
  that old order, it is not checked against your new request.

### When a purchase is refused [#when-a-purchase-is-refused]

Every refusal that can happen without spending money happens before anything is charged.

| Status                     | Meaning                                                          |
| -------------------------- | ---------------------------------------------------------------- |
| `403 feature_disabled`     | Phone number access is switched off for that account.            |
| `409 kyc_incomplete`       | The region needs identity verification and it is not finished.   |
| `409 number_unavailable`   | Someone claimed the number first. Search again and pick another. |
| `409 in_progress`          | A purchase for this number, or under this key, is still running. |
| `402 insufficient_balance` | The wallet cannot cover the rental. Nothing was charged.         |

## Identity verification [#identity-verification]

Some regions require the account to be verified before it can buy. India is one: the check is
an Aadhaar eKYC, so it completes in minutes.

Verification done in the dashboard counts, it is the same gate either way.

## List and release [#list-and-release]

```http
GET  /api/v1/phone_number/list
POST /api/v1/phone_number/release   { "phone_number": "+911155590077" }
```

Releasing gives the number up and stops its rental, so it is not charged at the next renewal.

## Reference [#reference]

Full request and response schemas, with a playground, are in the
[API reference](/docs/api-reference/phone-numbers/searchPhoneNumbers).