发送 SMS

用一套 API 发送 你的每一条短信。

设置时长:
Cursor

通过同一套 SMS API 发送一条消息或一百条。SDK 会在发送前计算段数,替你选择 GSM-7 或 Unicode,而且每次发送都是幂等的,并在每个投递状态上提供 webhook。

send-notification.ts
202 · 0.4s
import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });

const { data, error } = await bird.sms.send({
  from:     "Bird",
  to:       "+31612345678",
  text:     "Your order #4821 has shipped. Track it: bird.ly/t/4821x",
  category: "transactional",
}).safe();

if (error) throw error;
console.log(data.id);
// → "sms_01m11jw130e7svjzv70kgqr38w"
Hi Ada, reminder of your appointment tomorrow at 14:30 with Dr. Kowalski.
Your order #4821 has shipped. Track it: bird.ly/t/4821x
Your subscription renews on 3 Sep for €12/mo. Manage it here: bird.ly/account

五分钟内发送你的第一条 SMS。

用你已经在使用的语言。

发送是 Bird SMS API 的核心。第一次发送会发往一个官方测试接收方(+15005550006),因此你可以在开通号码之前交付一项 CI 检查并接入 webhook。

1
2
3
4
5
6
7
const msg = await bird.sms.send({
  from: "+15557654321",
  to: "+14155550100",
  text: "Your verification code is 123456.",
  category: "authentication",
});
console.log(msg.id, msg.status);

五件你无需自己构建的事。

每个 Bird 渠道上相同的约定。

  1. 01

    发送前计算段数。

    SDK 会测量编码后的长度并告诉你一条消息要花费多少段,因此一个意外字符永远不会悄无声息地把一条短信拆成三条。

  2. 02

    GSM-7 和 Unicode,替你决定。

    纯文本走 GSM-7;一个表情符号或非拉丁文字会把整条消息翻转为 UCS-2。Bird 会选择编码,并在单个字符改变成本时提醒你。

  3. 03

    在一次调用中批量发送。

    在一个请求中发送许多相互独立的消息,每条都有各自的接收方和文本,并作为一个整体进行校验,因此你永远不会发送一半。

  4. 04

    按约定幂等。

    每次发送都接受一个幂等键,因此超时后重试的请求会返回原始结果,而不是给某人发两次短信。

  5. 05

    在每次状态变更上提供一个 webhook。

    已排队、已发送、已投递、失败。每一个都经过 HMAC 签名、防重放、幂等,在每个渠道上都是相同的信封。

已经在别处发送了?切换客户端,保留调用。

结构几乎不变:换掉客户端,保留你的 from、to 和 text,把你的 webhook 指向一个端点。与你的邮件、语音和 WhatsApp 发送使用相同的鉴权模型。

twilio.ts
Twilio
import twilio from "twilio";

const client = twilio(accountSid, authToken);

await client.messages.create({
  from: "+14155550172",
  to:   "+15005550006",
  body: "Your code is 123456.",
});
bird.ts
Bird
import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });

await bird.sms.send({
  from:     "+14155550172",
  to:       "+15005550006",
  text:     "Your code is 123456.",
  category: "authentication",
});

在运营商之前就知道成本。

A GSM-7 message fits 160 characters per segment; a single emoji or non-Latin character flips the whole message to UCS-2 and drops that to 70. Bird counts the segments when it accepts the send and returns the breakdown in the response, so the number you are billed on is in hand before the carrier ever sees the message, and a concatenated message is always a deliberate choice.

segments.ts
200 · 1 segment
const { data, error } = await bird.sms.send({
  from:     "Bird",
  to:       "+31612345678",
  text:     "Your code is 123456.",
  category: "authentication",
}).safe();
if (error) throw error;

console.log(data.segments);
// → { characters: 20, count: 1, encoding: "GSM_7BIT" }

一条消息或一百条,一次调用。

在一个请求中批量发送相互独立的消息,每条都有各自的接收方和文本。批次会作为一个整体进行校验:一个坏号码会以 422 拒绝整个调用,因此你永远不会发送一半。一个幂等键让整个请求可安全重试。

reminders.ts
202 · batch
const { data: batch, error } = await bird.sms
  .sendBatch(
    users.map((u) => ({
      from: "Bird",
      to:   u.phone,
      text: `Hi ${u.name}, your appointment is tomorrow at ${u.time}.`,
    })),
    { idempotencyKey: `reminders-${runId}` },
  )
  .safe();

if (error) throw error;
console.log(`queued ${batch.data.length} messages`);

观察每条消息贯穿其完整生命周期。

一次发送会立即返回 202;结果会以 webhook 形式送达。验证一个签名,按 type 进行分支:与你已经为邮件、语音和 WhatsApp 处理的相同信封。

app/api/webhooks/bird/route.ts
signed
import { bird } from "@/lib/bird";

export async function POST(req: Request) {
  const event = bird.webhooks.unwrap(
    await req.text(),
    Object.fromEntries(req.headers),
  );

  switch (event.type) {
    case "sms.delivered":
      await markDelivered(event.data.sms_id);
      break;
    case "sms.failed":
      await flag(event.data.to, event.data.error?.description);
      break;
  }

  return new Response(null, { status: 204 });
}

失败的发送和 STOP 回复会自动更新你的抑制列表,因此一个坏号码永远不会让你付出两次代价。

  • sms.accepted已被 API 接受并排队等待交付给运营商。
  • sms.sent已提交给目的地运营商的 SMSC。
  • sms.delivered已从运营商收到投递回执(DLR)。
  • sms.failed永久失败:运营商拒绝、号码无效或触发屏蔽规则。

在文档中深入了解。

接入 webhook,用 幂等键 让每次发送都可安全重试,并阅读 错误参考,以便用正确的方式处理每一种失败。

全球约 40% 的商业 SMS 已经运行在 Bird 之上。

发送是 Bird SMS API 的一项能力:号码、双向入站、合规、路由和分析都随它一同提供,运行在我们已经运营十年的基础设施之上。

从一个渠道开始。
准备好后,再添加其他渠道。

测试 API 密钥即刻可用。添加支付方式并验证发送者身份后,即可解锁生产环境。

正在使用 Claude Code、Cursor 或 Codex?复制一条设置提示,您的智能代理即可自动安装 Bird CLI 和相关技能。选择您的工具:

Cursor