快速入门
- 在控制台中创建账户并充值余额。
- 打开API密钥并创建一个密钥。密钥在首次充值到账后即可创建。密钥仅显示一次;请妥善保存。
- 向
/sms发送POST请求,包含号码和短信内容。读取返回的营销活动ID,然后通过控制台或Webhook跟踪送达情况。
身份验证
除公开费率列表外,每个请求都需在Authorization头中携带您的密钥。密钥以sbk_live_开头。新密钥会立即替换旧密钥。
Authorization: Bearer sbk_live_YOUR_KEY发送短信
POST/sms
创建营销活动,从余额中扣除费用并排队发送每条消息。号码会被清理和去重;无法使用的号码会返回在dropped中并附上原因,且不收费。
| 字段 | 类型 | 说明 |
|---|---|---|
to必填 | 字符串或数组 | 一个号码或最多10,000个号码的数组,国际格式,例如"+447700900461" |
text必填 | 字符串 | 短信内容,最多10个分段。GSM-7编码每段160字符,UCS-2编码每段70字符 |
schedule_at可选 | 字符串 | ISO 8601时间,从5分钟后到60天内。省略则立即发送 |
client_ref可选 | 字符串 | 您的自定义参考信息,最多64个a-z A-Z 0-9 _ . : -字符,将在报告和Webhook中返回 |
opt_out可选 | 布尔值 | true会在短信末尾附加您在账户设置中设置的退订信息 |
curl -X POST https://sendbulksms.cc/api/v1/sms \
-H "Authorization: Bearer sbk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": ["+447700900461", "+5511955550123"],
"text": "Hi, your order 4821 ships today.",
"client_ref": "orders-4821"
}'const res = await fetch("https://sendbulksms.cc/api/v1/sms", {
method: "POST",
headers: { Authorization: "Bearer " + process.env.SENDBULKSMS_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ to: ["+447700900461", "+5511955550123"], text: "Hi, your order 4821 ships today.", client_ref: "orders-4821" }),
});
const campaign = await res.json();
console.log(res.status, campaign.id, campaign.cost);import os, requests
r = requests.post(
"https://sendbulksms.cc/api/v1/sms",
headers={"Authorization": "Bearer " + os.environ["SENDBULKSMS_KEY"]},
json={"to": ["+447700900461", "+5511955550123"], "text": "Hi, your order 4821 ships today.", "client_ref": "orders-4821"},
timeout=30,
)
print(r.status_code, r.json()["id"])<?php
$ch = curl_init("https://sendbulksms.cc/api/v1/sms");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("SENDBULKSMS_KEY"), "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode(["to" => ["+447700900461", "+5511955550123"], "text" => "Hi, your order 4821 ships today.", "client_ref" => "orders-4821"]),
]);
$campaign = json_decode(curl_exec($ch), true);
echo $campaign["id"];响应:营销活动及其成本和前1,000条消息。 通过营销活动消息获取更多信息。
HTTP/1.1 201 Created
{
"id": "CP-7KQ2-M9XA-4HTD",
"status": "sending",
"source": "api",
"recipients": 2,
"segments": 1,
"encoding": "GSM-7",
"cost": "0.01078",
"refunded": "0.00000",
"client_ref": "orders-4821",
"scheduled_at": null,
"created_at": "2026-11-07T10:32:04.118Z",
"done_at": null,
"counts": { "queued": 2, "sent": 0, "delivered": 0, "failed": 0, "canceled": 0 },
"dropped": [],
"balance": "248.30422",
"messages": [
{ "id": "SM-2RBW-8MZN-QF6K", "campaign_id": "CP-7KQ2-M9XA-4HTD", "to": "+447700900461", "country": "GB", "parts": 1, "price": "0.00819", "status": "queued", "error": null, "created_at": "2026-11-07T10:32:04.118Z", "sent_at": null, "done_at": null }
]
}估算发送成本
POST/estimate
接收与/sms相同的请求体,返回收件人、分段、编码、总成本和每个国家的成本,但不扣费或发送。
{ "recipients": 2, "dropped": [], "segments": 1, "encoding": "GSM-7", "cost": "0.01078", "balance": "248.31500",
"countries": [ { "country": "GB", "recipients": 1, "cost": "0.00819" }, { "country": "BR", "recipients": 1, "cost": "0.00259" } ] }消息状态
GET/sms/{message_id}
返回一条消息:号码、国家、分段、价格、状态、失败消息的错误以及每个步骤的时间。
营销活动
GET/campaigns/{campaign_id}
营销活动及其成本、退款和每种状态的消息数量。
GET/campaigns/{campaign_id}/messages?offset=0&limit=100
按排队顺序返回消息,每页最多1,000条。
POST/campaigns/{campaign_id}/cancel
取消尚未开始的已预约营销活动,并将其全额费用退还至余额。
余额和费率
GET/balance
{ "balance": "248.31500", "currency": "USD" }GET/rates
公开接口,无需密钥。每个国家及其电话代码和每分段价格。/rates/GB返回单个国家信息。
{ "updated": "2026-11-07", "rates": [ { "country": "GB", "name": "United Kingdom", "calling_code": "+44", "price": "0.00819", "currency": "USD", "unit": "SMS segment" } ] }送达Webhook
在控制台的API密钥下设置Webhook URL。当消息达到最终状态(送达或失败)时,我们会向其POST一份报告。请在8秒内以任何2xx状态响应;否则调用将在约11小时内重试最多8次。使用id忽略已处理的报告。
POST https://your-server.example/sms-status
Content-Type: application/json
X-SendBulkSMS-Signature: t=1794047524,v1=5f0c3b9e...
{
"event": "message.status",
"id": "evt_8c1d2e4f6a7b9c0d1e2f",
"created_at": "2026-11-07T10:32:09.004Z",
"data": {
"message_id": "SM-2RBW-8MZN-QF6K",
"campaign_id": "CP-7KQ2-M9XA-4HTD",
"to": "+447700900461",
"country": "GB",
"status": "delivered",
"error": null,
"parts": 1,
"price": "0.00819",
"client_ref": "orders-4821",
"done_at": "2026-11-07T10:32:08.912Z"
}
}在信任报告前验证签名:使用您的Webhook密钥对t + "." + raw body进行HMAC-SHA256哈希,并在恒定时间内比较,拒绝超过5分钟的报告。
import { createHmac, timingSafeEqual } from "node:crypto";
// raw = the request body exactly as received (string), header = X-SendBulkSMS-Signature
export function verify(raw, header, secret) {
const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header || "");
if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
const want = Buffer.from(createHmac("sha256", secret).update(m[1] + "." + raw).digest("hex"));
const got = Buffer.from(m[2]);
return want.length === got.length && timingSafeEqual(want, got);
}import hmac, hashlib, re, time
def verify(raw: bytes, header: str, secret: str) -> bool:
m = re.fullmatch(r"t=(\d+),v1=([0-9a-f]{64})", header or "")
if not m or abs(time.time() - int(m.group(1))) > 300:
return False
want = hmac.new(secret.encode(), m.group(1).encode() + b"." + raw, hashlib.sha256).hexdigest()
return hmac.compare_digest(want, m.group(2))<?php
function verify(string $raw, string $header, string $secret): bool {
if (!preg_match('/^t=(\d+),v1=([0-9a-f]{64})$/', $header, $m) || abs(time() - (int)$m[1]) > 300) return false;
$want = hash_hmac('sha256', $m[1] . '.' . $raw, $secret);
return hash_equals($want, $m[2]);
}状态
| 状态 | 含义 |
|---|---|
queued | 已接受并扣费,正在队列中等待发送 |
sent | 已提交至路由,等待送达报告 |
delivered | 网络已确认送达至终端设备 |
failed | 未送达;费用已退还,错误信息包含原因 |
canceled | 已取消未开始执行的定时群发任务;费用已退还 |
错误
错误使用HTTP状态码及JSON格式响应体:{ "error": { "code": "insufficient_balance", "message": "..." } }。返回错误的请求不会扣除余额
| HTTP | 代码 | 何时 |
|---|---|---|
| 400 | bad_request字段缺失或无效;错误信息会说明具体字段 | 字段缺失或无效;错误信息会说明具体字段 |
| 400 | no_valid_numbers"to"字段中所有号码均无效 | "to"字段中所有号码均无效 |
| 401 | unauthorizedAPI密钥缺失或无效 | API密钥缺失或无效 |
| 402 | insufficient_balance余额不足以支付本次发送;未扣除任何费用 | 余额不足以支付本次发送;未扣除任何费用 |
| 404 | not_found该群发任务、消息或接口不存在于您的账户 | 该群发任务、消息或接口不存在于您的账户 |
| 409 | not_scheduled仅可取消尚未开始执行的定时群发任务 | 仅可取消尚未开始执行的定时群发任务 |
| 413 | too_many_recipients单次请求包含超过10,000个号码 | 单次请求包含超过10,000个号码 |
| 429 | rate_limited该密钥每分钟请求超过300次 | 该密钥每分钟请求超过300次 |
| 500 | server_error请重试;失败的请求不会产生费用 | 请重试;失败的请求不会产生费用 |
限制
- 每个API密钥每分钟300次请求
- 每次发送请求最多10,000个号码;每条消息最多10个分段
- 消息按接收顺序发送,每个队列每分钟最多处理200条
- 可预约5分钟至60天内的发送时间
- 黑名单中的号码会被跳过并在dropped字段返回suppressed状态码;不计费