购买和释放号码
购买号码需要两次调用:先搜索某个国家的在售号码,然后下单购买你想要的号码。所有操作都需要一个具有 numbers 范围的 API 密钥,且组织中的首次购买需要完成身份验证。
搜索国家
搜索始终限定在一个国家内,因此 country_code 是必填项。可以通过 number_type、capabilities 或国内号码的 prefix 进一步缩小范围。
// 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);
}# The search is always country-scoped, so country_code is required.
page = client.numbers.available.list(country_code="GB", capabilities=["sms", "voice"])
for candidate in page.data:
print(candidate.number, candidate.number_type)for candidate, err := range client.Numbers.Available.List(context.Background(), bird.NumbersAvailableListParams{
CountryCode: "GB",
Capabilities: []string{"sms", "voice"},
}) {
if err != nil {
log.Fatal(err)
}
fmt.Println(candidate.Number, candidate.NumberType)
}// The search is always country-scoped, so country_code is required.
$page = $bird->numbers->available->list([
'country_code' => 'GB',
'capabilities' => ['sms', 'voice'],
]);
foreach ($page as $candidate) {
echo $candidate->getNumber(), ' ', $candidate->getNumberType(), "\n";
}curl "https://us1.platform.bird.com/v1/numbers/available?country_code=GB" \
-H "Authorization: Bearer bk_us1_..."使用与你的密钥 bk_{region}_ 前缀匹配的区域主机:https://us1.platform.bird.com 或 https://eu1.platform.bird.com。
每条结果只包含你选择号码所需的信息:
{
"data": [
{
"number": "+447700900123",
"country_code": "GB",
"number_type": "mobile",
"capabilities": ["sms", "voice"]
}
],
"next_cursor": null,
"prev_cursor": null
}我们自有库存会优先返回并正常分页。最后一页可能包含运营商实时提供的号码,因此刚刚列出的号码在你下单时可能已经被买走。
要在下单前确认号码仍然可用,请通过 GET /v1/numbers/available/{number} 重新读取该号码。返回 404 表示该号码当前不可购买,无论是运营商已撤回还是我们自己的库存已将其预留。重新检查与搜索共用同一个 numbers_availability 速率限制,因此只对即将下单的候选号码做重新检查,而不是对每个结果都检查一遍。
下单购买号码
将搜索结果中的号码传给 POST /v1/numbers/orders。关于重试保护,请参阅幂等性。
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);
}order = client.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 completed or failed.
if order.status == "completed":
print("allocated as", order.number_id)
else:
print("still", order.status, "; poll", order.id)order, err := client.Numbers.Orders.Create(context.Background(), bird.NumbersOrdersCreateParams{
Number: "+447700900201",
})
if err != nil {
log.Fatal(err)
}
// An order that has to wait on a carrier comes back without a NumberId.
// Poll it until it is completed or failed.
fmt.Println(order.Status, order.Id)$order = $bird->numbers->orders->create(
(new NumbersOrderCreate())->setNumber('+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->getStatus() === 'completed') {
echo 'allocated as ', $order->getNumberId(), "\n";
} else {
echo 'still ', $order->getStatus(), '; poll ', $order->getId(), "\n";
}curl -X POST "https://us1.platform.bird.com/v1/numbers/orders" \
-H "Authorization: Bearer bk_us1_..." \
-H "Content-Type: application/json" \
-d '{"number": "+447700900123"}'大多数订单在请求内即可完成,返回 201,号码已归你所有:
{
"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。
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 ?? "");order = client.numbers.orders.get("nor_01krdgeqcxet5s7t44vh8rt9mg")
# failure_reason says what went wrong, and only ever on a failed order.
print(order.status, order.failure_reason or "")order, err := client.Numbers.Orders.Get(context.Background(), "nor_01krdgeqcxet5s7t44vh8rt9mg")
if err != nil {
log.Fatal(err)
}
// FailureReason says what went wrong, and only ever on a failed order.
fmt.Println(order.Status)$order = $bird->numbers->orders->get('nor_01krdgeqcxet5s7t44vh8rt9mg');
// failure_reason says what went wrong, and only ever on a failed order.
echo $order->getStatus(), ' ', $order->getFailureReason() ?? '', "\n";curl "https://us1.platform.bird.com/v1/numbers/orders/nor_01m0da22b0e39anhzyhtw3gzdg" \
-H "Authorization: Bearer bk_us1_..."订单依次经过 charging、ordering 和 pending,然后最终确定。当状态为 failed 时,failure_reason 会用简明语言说明失败原因。已扣除的开通费不会退还,因此失败的订单可能仍会产生费用;如遇此情况请联系支持团队。
释放号码
释放号码会停止月度扣费,该号码也将不再为你工作。只有 dedicated 状态的号码才能被释放,释放后的号码不会立即重新上架出售。
// 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");# Releasing stops the monthly charge and the number stops working for you.
# Only a dedicated number can be released; a shared one answers E14002.
client.numbers.release("nda_01krdgeqcxet5s7t44vh8rt9mg")// Only a dedicated number can be released; a shared one answers E14002.
if err := client.Numbers.Release(context.Background(), "nda_01krdgeqcxet5s7t44vh8rt9mg"); err != nil {
log.Fatal(err)
}// Releasing stops the monthly charge and the number stops working for you.
// Only a dedicated number can be released; a shared one answers E14002.
$bird->numbers->release('nda_01krdgeqcxet5s7t44vh8rt9mg');curl -X DELETE "https://us1.platform.bird.com/v1/numbers/nda_7eqywfwzxwa1za9n8wp7e1xkr8" \
-H "Authorization: Bearer bk_us1_..."释放成功后返回 204,无响应体。
订单被拒绝时
四种拒绝原因涵盖了几乎所有购买失败的情况。
402 加 E03000 表示钱包余额不足以支付该号码。充值后重新下单。此时不会创建订单,因此不会产生扣费。
412 表示该组织尚未完成首次购买所需的身份验证。完成验证后重试。
409 加 E14000 表示在你选择期间该号码已被他人购买。重新搜索并选择另一个号码。
409 加 E14001 表示你有太多订单仍在处理中。等待其中一个完成后再下单。
后续步骤
- 号码概览介绍号码上各字段的含义。
- Numbers API 参考文档记录了所有操作和字段。
- 幂等性介绍幂等键如何确保重试下单的安全性。