通过同一套 SMS API 发送一条消息或一百条。SDK 会在发送前计算段数,替你选择 GSM-7 或 Unicode,而且每次发送都是幂等的,并在每个投递状态上提供 webhook。
import { BirdClient } from "@messagebird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const code = generateOtp();
const { data, error } = await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: `Your Bird verification code is ${code}. Reply STOP to opt out.`,
}).safe();
if (error) throw error;
console.log(data.id);
// → "sms_4kT01Lq2m..."Today at 2:14 PM
五分钟内发送你的第一条 SMS。
用你已经在使用的语言。
发送是 Bird SMS API 的核心。第一次发送会发往一个官方测试接收方(+15005550006),因此你可以在开通号码之前交付一项 CI 检查并接入 webhook。
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: "+15005550006",
text: "Hello from Node.",
}).safe();五件你无需自己构建的事。
每个 Bird 渠道上相同的约定。
- 01
发送前计算段数。
SDK 会测量编码后的长度并告诉你一条消息要花费多少段,因此一个意外字符永远不会悄无声息地把一条短信拆成三条。
- 02
GSM-7 和 Unicode,替你决定。
纯文本走 GSM-7;一个表情符号或非拉丁文字会把整条消息翻转为 UCS-2。Bird 会选择编码,并在单个字符改变成本时提醒你。
- 03
在一次调用中批量发送。
在一个请求中发送许多相互独立的消息,每条都有各自的接收方和文本,并作为一个整体进行校验,因此你永远不会发送一半。
- 04
按约定幂等。
每次发送都接受一个幂等键,因此超时后重试的请求会返回原始结果,而不是给某人发两次短信。
- 05
在每次状态变更上提供一个 webhook。
已排队、已发送、已投递、失败。每一个都经过 HMAC 签名、防重放、幂等,在每个渠道上都是相同的信封。
已经在别处发送了?切换客户端,保留调用。
结构几乎不变:换掉客户端,保留你的 from、to 和 text,把你的 webhook 指向一个端点。与你的邮件、语音和 WhatsApp 发送使用相同的鉴权模型。
import twilio from "twilio";
const client = twilio(accountSid, authToken);
await client.messages.create({
from: "+14155550172",
to: "+15005550006",
body: "Your code is 123456.",
});import { BirdClient } from "@messagebird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: "Your code is 123456.",
});在运营商之前就知道成本。
一条 GSM-7 消息每段可容纳 160 个字符;一个表情符号或非拉丁字符会把整条消息翻转为 UCS-2,并将其降至 70 个。SDK 会在每次发送时报告编码和段数,因此计费永远不会出乎意料,拼接消息也始终是一个有意为之的选择。
const { data } = await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: "Your code is 123456.",
}).safe();
console.log(data.encoding); // → "GSM-7"
console.log(data.segments); // → 1一条消息或一百条,一次调用。
在一个请求中批量发送相互独立的消息,每条都有各自的接收方和文本。批次会作为一个整体进行校验:一个坏号码会以 422 拒绝整个调用,因此你永远不会发送一半。一个幂等键让整个请求可安全重试。
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 处理的相同信封。
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.reason);
break;
}
return new Response(null, { status: 204 });
}失败的发送和 STOP 回复会自动更新你的抑制列表,因此一个坏号码永远不会让你付出两次代价。
sms.queued已被 API 接受并排队等待交付给运营商。sms.sent已提交给目的地运营商的 SMSC。sms.delivered已从运营商收到投递回执(DLR)。sms.failed永久性失败——运营商拒绝、号码无效或命中抑制。