# 购买和释放号码

购买号码需要两次调用：先搜索某个国家的在售号码，然后下单购买你想要的号码。所有操作都需要一个具有 `numbers` 范围的 API 密钥，且组织中的首次购买需要完成身份验证。

## 搜索国家

搜索始终限定在一个国家内，因此 `country_code` 是必填项。可以通过 `number_type`、`capabilities` 或国内号码的 `prefix` 进一步缩小范围。

**TypeScript**

```typescript
// The search is always country-scoped, so country_code is required.
const page = await bird.numbers.available.list({
  country_code: "GB",
  capabilities: ["sms", "voice"],
});
for (const candidate of page.data) {
  console.log(candidate.number, candidate.number_type);
}
```

Examples: [TypeScript](/zh-sg/wendang/guides/numbers/buying-numbers.ts.md) · [Python](/zh-sg/wendang/guides/numbers/buying-numbers.py.md) · [Go](/zh-sg/wendang/guides/numbers/buying-numbers.go.md) · [PHP](/zh-sg/wendang/guides/numbers/buying-numbers.php.md) · [cURL](/zh-sg/wendang/guides/numbers/buying-numbers.curl.md)

使用与你的密钥 `bk_{region}_` 前缀匹配的区域主机：`https://us1.platform.bird.com` 或 `https://eu1.platform.bird.com`。

每条结果只包含你选择号码所需的信息：

```json
{
  "data": [
    {
      "number": "+447700900123",
      "country_code": "GB",
      "number_type": "mobile",
      "capabilities": ["sms", "voice"]
    }
  ],
  "next_cursor": null,
  "prev_cursor": null
}
```

我们自有库存会优先返回并正常分页。最后一页可能包含运营商实时提供的号码，因此刚刚列出的号码在你下单时可能已经被买走。

要在下单前确认号码仍然可用，请通过 [`GET /v1/numbers/available/{number}`](/docs/api/reference/get-available-number) 重新读取该号码。返回 `404` 表示该号码当前不可购买，无论是运营商已撤回还是我们自己的库存已将其预留。重新检查与搜索共用同一个 `numbers_availability` 速率限制，因此只对即将下单的候选号码做重新检查，而不是对每个结果都检查一遍。

## 下单购买号码

将搜索结果中的号码传给 [`POST /v1/numbers/orders`](/docs/api/reference/create-numbers-order)。关于重试保护，请参阅[幂等性](/docs/guides/idempotency)。

**TypeScript**

```typescript
const order = await bird.numbers.orders.create({ number: "+447700900201" });
// Most orders finish inside the request. One that has to wait on a carrier
// comes back without a number_id. Poll it until it is completed or failed.
if (order.status === "completed") {
  console.log("allocated as", order.number_id);
} else {
  console.log("still", order.status, "; poll", order.id);
}
```

Examples: [TypeScript](/zh-sg/wendang/guides/numbers/buying-numbers.ts.md) · [Python](/zh-sg/wendang/guides/numbers/buying-numbers.py.md) · [Go](/zh-sg/wendang/guides/numbers/buying-numbers.go.md) · [PHP](/zh-sg/wendang/guides/numbers/buying-numbers.php.md) · [MCP](/zh-sg/wendang/guides/numbers/buying-numbers.mcp.md) · [cURL](/zh-sg/wendang/guides/numbers/buying-numbers.curl.md)

大多数订单在请求内即可完成，返回 `201`，号码已归你所有：

```json
{
  "id": "nor_01m0da22b0e39anhzyhtw3gzdg",
  "number": "+447700900123",
  "country_code": "GB",
  "number_type": "mobile",
  "status": "completed",
  "number_id": "nda_7eqywfwzxwa1za9n8wp7e1xkr8",
  "failure_reason": null,
  "completed_at": "2026-08-19T15:25:56.479320Z",
  "created_at": "2026-08-19T15:25:56.448051Z",
  "updated_at": "2026-08-19T15:25:56.479320Z"
}
```

`number_id` 是后续所有操作的标识：读取号码和释放号码。

## 轮询未完成的订单

需要等待运营商处理的订单会返回 `202`，此时 `number_id` 仍为 `null`。反复读取该订单，直到 `status` 变为 `completed` 或 `failed`。

**TypeScript**

```typescript
const order = await bird.numbers.orders.get("nor_01krdgeqcxet5s7t44vh8rt9mg");
// failure_reason says what went wrong, and only ever on a failed order.
console.log(order.status, order.failure_reason ?? "");
```

Examples: [TypeScript](/zh-sg/wendang/guides/numbers/buying-numbers.ts.md) · [Python](/zh-sg/wendang/guides/numbers/buying-numbers.py.md) · [Go](/zh-sg/wendang/guides/numbers/buying-numbers.go.md) · [PHP](/zh-sg/wendang/guides/numbers/buying-numbers.php.md) · [MCP](/zh-sg/wendang/guides/numbers/buying-numbers.mcp.md) · [cURL](/zh-sg/wendang/guides/numbers/buying-numbers.curl.md)

订单依次经过 `charging`、`ordering` 和 `pending`，然后最终确定。当状态为 `failed` 时，`failure_reason` 会用简明语言说明失败原因。已扣除的开通费不会退还，因此失败的订单可能仍会产生费用；如遇此情况请联系支持团队。

## 释放号码

释放号码会停止月度扣费，该号码也将不再为你工作。只有 `dedicated` 状态的号码才能被释放，释放后的号码不会立即重新上架出售。

**TypeScript**

```typescript
// Releasing stops the monthly charge and the number stops working for you.
// Only a dedicated number can be released; a shared one answers E14002.
await bird.numbers.release("nda_01krdgeqcxet5s7t44vh8rt9mg");
```

Examples: [TypeScript](/zh-sg/wendang/guides/numbers/buying-numbers.ts.md) · [Python](/zh-sg/wendang/guides/numbers/buying-numbers.py.md) · [Go](/zh-sg/wendang/guides/numbers/buying-numbers.go.md) · [PHP](/zh-sg/wendang/guides/numbers/buying-numbers.php.md) · [MCP](/zh-sg/wendang/guides/numbers/buying-numbers.mcp.md) · [cURL](/zh-sg/wendang/guides/numbers/buying-numbers.curl.md)

释放成功后返回 `204`，无响应体。

## 订单被拒绝时

四种拒绝原因涵盖了几乎所有购买失败的情况。

`402` 加 [`E03000`](/docs/api/errors/E03000) 表示钱包余额不足以支付该号码。充值后重新下单。此时不会创建订单，因此不会产生扣费。

`412` 表示该组织尚未完成首次购买所需的身份验证。完成验证后重试。

`409` 加 [`E14000`](/docs/api/errors/E14000) 表示在你选择期间该号码已被他人购买。重新搜索并选择另一个号码。

`409` 加 [`E14001`](/docs/api/errors/E14001) 表示你有太多订单仍在处理中。等待其中一个完成后再下单。

## 后续步骤

- [号码概览](/docs/guides/numbers/overview)介绍号码上各字段的含义。
- [Numbers API 参考文档](/docs/api/reference/create-numbers-order)记录了所有操作和字段。
- [幂等性](/docs/guides/idempotency)介绍幂等键如何确保重试下单的安全性。

## Related resources

- [What is a virtual phone number (VMN)?](/explained/numbers/what-is-a-virtual-phone-number) (answer)
- [SMS numbers](/sms-api/features/numbers) (product)
- [Number types](/docs/guides/numbers/number-types) (docs)

[Get an implementation brief](/learn/workspace?topic=phone-numbers)
