发送 SMS
本指南介绍单条发送端点 POST /v1/sms/messages。构建一个包含收件人、发送方、正文和类别的 JSON 载荷。Bird 返回 202 Accepted 及消息 ID,并异步投递。每个请求向一个收件人发送一条消息。如需一次发送多条消息,请使用批量发送。如需发送模板而非自定义文本,请用 template 对象替代 text、category 和 from。
发送前:启用目的地国家
您的工作区有一个默认拒绝的目的地白名单,初始仅启用您所在组织的本国。Bird 会在解析发送方之前,以 422 SMSDestinationNotEnabled 拒绝发往其他国家的请求。请在控制台的 SMS > Destinations 中启用您服务的国家。
最简发送
最小的有效自由文本载荷包含一个 to 收件人、一个 from 发送方、一个 text 正文和一个 category。
const msg = await bird.sms.send({
from: "+15557654321",
to: "+14155550100",
text: "Your verification code is 123456.",
category: "authentication",
});
console.log(msg.id, msg.status);msg = client.sms.send(
from_="+15557654321",
to="+15551234567",
text="Your verification code is 123456.",
category="authentication",
)
print(msg.id, msg.status)msg, err := client.Sms.Send(context.Background(), bird.SmsSendParams{
From: "+15557654321",
To: "+15551234567",
Text: "Your verification code is 123456.",
Category: bird.SMSCategoryAuthentication,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id, *msg.Status)$message = $bird->sms->send(
from: '+15557654321',
to: '+15551234567',
text: 'Your verification code is 123456.',
category: 'authentication',
);
echo $message->getId(), ' ', $message->getStatus();bird sms send --body-file - <<'JSON'
{
"to": "+14155550100",
"from": "+15557654321",
"text": "Your verification code is 123456.",
"category": "authentication",
"options": {
"smart_encoding": true
},
"tags": [
{
"name": "campaign",
"value": "signup"
}
],
"metadata": {
"user_id": "usr_12345"
}
}
JSONcurl -X POST https://eu1.platform.bird.com/v1/sms/messages \
-H "Authorization: Bearer bk_eu1_..." \
-H "Content-Type: application/json" \
-d '{
"to": "+31612345678",
"from": "Bird",
"text": "Your Bird verification code is 481920. It expires in 10 minutes.",
"category": "authentication"
}'使用您的区域主机(https://us1.platform.bird.com 或 https://eu1.platform.bird.com)并搭配对应的 bk_{region}_... 密钥。响应为已接受的消息:
代码示例
{
"id": "sms_01ky7qmwgpfkybj9ecrnwjx714",
"direction": "outbound",
"status": "accepted",
"to": "+31612345678",
"from": "Bird",
"text": "Your Bird verification code is 481920. It expires in 10 minutes.",
"category": "authentication",
"segments": { "count": 1, "encoding": "GSM_7BIT", "characters": 64 },
"cost": null,
"carrier": null,
"mcc_mnc": null,
"sent_at": null,
"delivered_at": null,
"created_at": "2026-07-23T14:56:34.326Z"
}构建载荷
收件人
to 是一个 E.164 格式的收件人:以 + 开头,后接国家代码和用户号码,例如 +31612345678。一条消息只发给一个收件人,不支持 cc、bcc 或收件人数组。如需发送给多人,请使用批量发送。
发送方
from 在自由文本发送中为必填字段,是收件人看到的发送方。它有两种形式,哪种可用取决于目的地国家:
- 字母数字发送者 ID:3 到 11 个字母、数字、空格、短横线、下划线或点,至少包含一个字母,且首尾不能是分隔符,例如 Bird 或 Acme-Co。必须包含字母,因此纯数字加标点的字符串(如 555 555)会被拒绝。部分国家要求注册,其他国家(包括美国)不支持字母数字发送者。收件人无法回复此类发送者。
- 您的工作区拥有的号码,使用 E.164 格式或纯数字。任何全数字的 from 都会被视为数字号码,并在您的发送方中查找,因此您不拥有的任意号码会被拒绝。它作为长号码、免费电话号码还是短号码使用,取决于号码本身,而非您输入了多少位数字。一个 6 位的 from 并非因为有 6 位数字就是短号码;只有当您拥有的号码本身是短号码时,它才是短号码。
对目的地无效的发送方会被拒绝,返回 422 并注明原因(例如在不支持字母数字发送方的地区返回 SMSAlphaNotSupported)。在模板发送中,不接受 from:Bird 会根据目的地和类别自动选择发送方。
申请发送方 ID、查看各国对发送方的要求以及按国家注册的流程,请参阅 SMS 发送方 ID。
正文和类别
text 是消息正文,至少一个字符。它按分段计费和投递;每次发送上限为 12 个分段(约 1,836 个 GSM-7 字符,若正文使用扩展 UCS-2 编码则为 804 个字符)。超出上限的正文会以 422 被拒绝,而非被截断。
category 在自由文本发送中为必填字段,将消息分类为 transactional、marketing、authentication 或 service。它告知 Bird 和运营商您发送消息的原因。一次性验证码使用 authentication;促销消息使用 marketing。请选择与消息用途匹配的类别。
标签和元数据
两者都用于将您自己的数据附加到发送中,但用途不同:
- tags 是结构化的 {name, value} 键值对(每次发送最多 20 个;名称 1 到 32 个字符,值 1 到 64 个字符,仅限 ASCII [A-Za-z0-9_-],区分大小写,名称在同一次发送中唯一)。它们是一等过滤维度:可以按标签过滤消息列表。适用于低基数标签,如 campaign 或 experiment_variant。
- metadata 是任意 JSON 对象(序列化后最大 2 KB)。它会被存储,在 API 读取时返回,并在每个 webhook 事件中回传,但不是过滤维度。适用于往返上下文:内部 ID、外键,以及您希望在每个事件中回传的任何数据。
代码示例
{
"tags": [{ "name": "campaign", "value": "spring-2026" }],
"metadata": { "user_id": "usr_12345", "order_id": "ord_98765" }
}字段参考
| 字段 | 类型 | 必填 | 限制 / 说明 |
|---|---|---|---|
| to | string (E.164) | 是 | 每条消息一个收件人 |
| from | string | 是* | 自有 E.164 号码、字母数字发送方 ID(3–11 个字符,至少一个字母)或短号码(5–6 位数字) |
| text | string | 是* | 至少 1 个字符;上限 12 个分段 |
| category | string | 是* | transactional、marketing、authentication 或 service |
| tags | {name, value}[] | 否 | 最多 20 个;名称 1–32 个字符,值 1–64 个字符;仅限 [A-Za-z0-9_-] |
| metadata | object | 否 | 任意 JSON,序列化后最大 2 KB |
| options | object | 否 | 每条消息的处理设置。smart_encoding 是唯一可用的选项;参见分段和编码 |
* 在自由文本发送中为必填。模板发送会由模板提供正文、类别和发送方,并拒绝这三个字段。
使用模板发送
无需自行编写 text,而是将发送的 template 对象设置为引用 Bird 的内置模板之一。模板提供正文、类别和发送方,因此 text、category、from 和 media_urls 不能同时使用。模板目录、每个模板的变量以及完整的模板发送约定请参阅 SMS 模板。
分段和编码
SMS 按分段计费。适合 GSM-7 编码的消息,单个分段可容纳 160 个字符;UCS-2(由表情符号、中日韩文字或其他非 GSM 字符触发)降至 70 个字符。较长的消息会被拆分为多段,每段容量略低。每个响应都会报告解析后的 segments:计费 count、encoding 和字符数。分段是计费单位;参见费用。
当排版字符是正文超出 GSM-7 范围的唯一原因时,智能编码可以减少分段数。将 options.smart_encoding 设置为 true,Bird 会在发送前将弯引号、破折号、省略号等字符替换为 GSM-7 等效字符。此功能默认关闭,因为它会更改您编写的正文。
完整字符集、扩展表中占两个位置的字符、表情符号大小、智能编码的替换内容以及分段计算方式,请参阅字符限制。
批量发送
POST /v1/sms/batches 可在一次请求中发送最多 100 条独立消息。批量请求使用 sms_batch 请求速率限制策略,与单条发送的 sms_send 策略相互独立。请求体是一个 JSON 对象,其 messages 数组包含构建载荷中所述的消息对象:
const result = await bird.sms.sendBatch({
messages: [
{
from: "+15557654321",
to: "+15551111111",
text: "Hi Alice!",
category: "marketing",
},
{
from: "+15557654321",
to: "+15552222222",
text: "Hi Bob!",
category: "marketing",
},
],
});batch = client.sms.send_batch(
messages=[
{
"from_": "+15557654321",
"to": "+15551111111",
"text": "Hi Alice!",
"category": "marketing",
},
{
"from_": "+15557654321",
"to": "+15552222222",
"text": "Hi Bob!",
"category": "marketing",
},
]
)
for msg in batch.data:
print(msg.id, msg.status)batch, err := client.Sms.SendBatch(context.Background(), bird.SmsSendBatchParams{
Messages: []bird.SmsSendParams{
{
From: "+15557654321", To: "+15551111111",
Text: "Hi Alice!", Category: bird.SMSCategoryMarketing,
},
{
From: "+15557654321", To: "+15552222222",
Text: "Hi Bob!", Category: bird.SMSCategoryMarketing,
},
},
})
if err != nil {
log.Fatal(err)
}
for _, msg := range batch.Data {
fmt.Println(msg.Id, *msg.Status)
}$batch = $bird->sms->sendBatch(messages: [
(new SMSMessageSendRequest())
->setFrom('+15557654321')
->setTo('+15551111111')
->setText('Hi Alice!')
->setCategory('marketing'),
(new SMSMessageSendRequest())
->setFrom('+15557654321')
->setTo('+15552222222')
->setText('Hi Bob!')
->setCategory('marketing'),
]);
foreach ($batch->getData() ?? [] as $item) {
echo $item->getId(), ' ', $item->getStatus(), "\n";
}curl -X POST "https://{region}.platform.bird.com/v1/sms/batches" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"to": "+15551111111",
"from": "+15557654321",
"text": "Hi Alice!",
"category": "marketing"
},
{
"to": "+15552222222",
"from": "+15557654321",
"text": "Hi Bob!",
"category": "marketing"
}
]
}'校验采用全有或全无策略:如果批次中任何一条消息无效,整个请求将以 422 被拒绝且不会发送任何消息,因此批次不会部分执行。成功时,202 响应按提交顺序在 data 下返回每条已接受的消息,并附带包含 accepted_count 的 summary。此后每条消息彼此独立:一个收件人的失败不会影响其他消息。
异步模型:202 的含义
发送成功后返回 202 Accepted,包含消息 ID 和 status: accepted。请求失败会立即返回:无效字段、正文超出分段上限、未启用的目的地国家或无效发送方会返回 422。工作区余额不足时会收到 402。
投递异步进行。当 Bird 将消息交给运营商时,消息状态变为 sent。随后,投递回执通过事件和 Webhook 及读取端点将状态设为 delivered、undelivered、failed 或 expired。这一设计带来三个影响:
- 费用在接受后定价。 消息上的 cost 在接受时为 null,待 Bird 在处理过程中完成定价后填充。回读该消息或等待投递事件即可查看当前已定价的费用;费用与计费介绍了各费用组成部分及某项保持未定价的情形。
- 消息可能在 202 之后被拒绝。 如果处理过程中扣费失败,消息最终状态为 rejected,并触发 sms.rejected Webhook,且不会向您计费;余额耗尽表现为 last_error.code: insufficient_balance。
- 读取可能短暂滞后于 202。 消息在 202 之后不久才在读取端点可见,因此发送后立即执行 404 查询会在片刻内自行解决。
保留字段
Bird 当前会以 422 SMSUnsupportedFeature 拒绝以下请求字段:
scheduled_at、validity_period、media_urls、messaging_profile_id、broadcast_id、campaign_id、audience_id、contact_id、topic_id、personalization、options.max_price_per_segment、options.track_clicks
发送时不要包含这些字段。
安全重试
在每次逻辑发送中附带唯一值的 Idempotency-Key 请求头。如果请求成功但未返回响应,使用相同的请求和密钥重放即可。Bird 会返回原始结果,而不会重复发送消息。有关密钥格式和保留期限,请参阅幂等性。
费用与计费
出站 SMS 按分段计费。您支付的金额取决于目的地国家和运营商;某些路由会附加第三方附加费,例如美国 10DLC 运营商费用。
消息的 cost 将费用拆分为命名组成部分。transaction_amount 是 Bird 承载消息所收取的费用,passthrough_amount 是转嫁的第三方费用,amount 是已定价组成部分的总和,币种为 currency_code。尚未定价的组成部分为 null 而非 "0.00000",因此附加费始终未能解析的消息,amount 仅为承载费用。消息参考记录了每个字段。
附加费为尽力解析。Bird 在记录投递回执时在限定窗口内解析附加费。如果在该窗口内未能解析,passthrough_amount 将永久保持 null:Bird 不会重试,amount 仍为承载费用。
入站 SMS 分两项计费:按分段的入站费率和适用时的入站运营商附加费。两项均在接收消息自身的 cost 中报告:费率为 transaction_amount,附加费为 passthrough_amount。与出站附加费不同,入站附加费在消息被接受时即完成定价,而非在投递时,因此不会后续补充。
在 SMS 日志中查看每条消息的费用和分段。
后续步骤
- SMS 模板:发送内置模板并让 Bird 选择发送方。
- SMS 日志:查找消息并检查其生命周期、分段和费用。
- 事件:在您的系统中接收投递事件。
- SMS 指标:监控投递率、失败率和已接受量。
- 幂等性:使用 Idempotency-Key 请求头安全重试。
- 发送您的第一条 SMS:一段视频,演示在控制面板中完成相同设置的过程
相关资源
继续查阅此主题的文档、指南和示例。资源为英文。