快速開始
- 在控制台建立帳戶並為餘額充值。
- 開啟 API 金鑰 並建立金鑰。首次充值後即可建立金鑰。金鑰僅顯示一次,請妥善保存。
- 發送 POST 請求至
/sms並提供號碼與簡訊內容。讀取回傳的活動 ID 後,可透過控制台或送達回報追蹤發送狀態。
身份驗證
除公開費率表外,所有請求需在 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 _ . : -),將顯示於報表與送達回報 |
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 筆訊息的活動資料。 使用 campaign messages 取得更多訊息。
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" } ] }送達回報
在控制台的 API 金鑰設定中指定回報網址。當訊息達最終狀態(送達或失敗)時,我們將 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天後的發送。
- 您的禁止發送清單上的號碼將被跳過,並以suppressed代碼返回於dropped中;不會扣除費用。