批量 SMS API v1
一個小型 REST API,用於從您的軟件發送批量 SMS:JSON 輸入輸出,Bearer 密鑰,與控制台相同的價格和檢查,以及簽名的送達報告 webhooks。 基礎 URL https://smsbulk.cc/rest/v1
概覽
每個請求最多可發送到 8,000 個號碼,每個號碼都有自己的合併值,API 會像控制台一樣為每個收件人計算合併後的文本價格。首先使用相同的內容請求報價以了解成本;報價不會發送或收取任何費用。時間為 ISO 8601 UTC 格式,金額為五位小數的美元字符串。
curl https://smsbulk.cc/rest/v1/send \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipients": [
{ "to": "+14155550142", "fields": { "name": "Maria" } },
{ "to": "+447400123456", "fields": { "name": "Tom" } }
],
"text": "Hi {{name}}, your order ships today.",
"client_ref": "order-batch-17"
}'const res = await fetch("https://smsbulk.cc/rest/v1/send", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
recipients: [
{ to: "+14155550142", fields: { name: "Maria" } },
{ to: "+447400123456", fields: { name: "Tom" } },
],
text: "Hi {{name}}, your order ships today.",
client_ref: "order-batch-17",
}),
});
const data = await res.json();
console.log(res.status, data.campaign?.id, data.campaign?.cost);import requests
res = requests.post(
"https://smsbulk.cc/rest/v1/send",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"recipients": [
{"to": "+14155550142", "fields": {"name": "Maria"}},
{"to": "+447400123456", "fields": {"name": "Tom"}},
],
"text": "Hi {{name}}, your order ships today.",
"client_ref": "order-batch-17",
},
timeout=30,
)
data = res.json()
print(res.status_code, data.get("campaign", {}).get("id"))<?php
$body = json_encode([
"recipients" => [
["to" => "+14155550142", "fields" => ["name" => "Maria"]],
["to" => "+447400123456", "fields" => ["name" => "Tom"]],
],
"text" => "Hi {{name}}, your order ships today.",
"client_ref" => "order-batch-17",
]);
$ch = curl_init("https://smsbulk.cc/rest/v1/send");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => $body,
]);
$data = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $data["campaign"]["id"] ?? "", PHP_EOL;認證
在控制台的 API 和 webhooks 下創建密鑰;密鑰在您首次充值後啟用。在每個請求中將其作為 Bearer token 發送。密鑰只顯示一次;您最多可以保留 5 個密鑰,並隨時撤銷任何一個。
Authorization: Bearer smsb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx費率
公開,無需密鑰。每個目的地或一個 ISO 代碼的每條 SMS 分段價格。
GEThttps://smsbulk.cc/rest/v1/rates
GEThttps://smsbulk.cc/rest/v1/rates/{ISO}
{
"country": "US",
"name": "United States",
"dial_code": "+1",
"rate": "0.00485",
"currency": "USD",
"per": "message segment"
}餘額
GEThttps://smsbulk.cc/rest/v1/credit
{ "credit": "125.40000", "currency": "USD", "account": "A418820037715" }報價
計算發送價格而不實際發送。使用與 Send 相同的內容。
POSThttps://smsbulk.cc/rest/v1/quote
| 欄位 | 類型 | 含義 |
|---|---|---|
| to | string or string[] | 單一號碼或列表。使用國際格式(帶+號)最安全;本地號碼需指定 default_country。 |
| recipients | object[] | 可替代 to:使用 { to, fields } 列表,其中 fields 用於填充合併欄位如 {{name}}。 |
| text | string | 訊息內容,合併後最多 2,000 個字符和 10 個分段。 |
| default_country | string | 用於不帶+號的號碼的 ISO 代碼(如 GB)。若未指定則使用設定中保存的默認值。 |
| opt_out | boolean | 將您保存的拒收聲明添加為最後一行(需先在設定中保存)。 |
{
"recipients": 2,
"messages": 2,
"segments": { "min": 1, "max": 1 },
"encoding": "GSM-7",
"total": "0.01240",
"currency": "USD",
"credit": "125.40000",
"credit_after": "125.38760",
"countries": [
{ "country": "US", "recipients": 1, "rate": "0.00485", "segments": 1, "subtotal": "0.00485" },
{ "country": "GB", "recipients": 1, "rate": "0.00755", "segments": 1, "subtotal": "0.00755" }
],
"left_out": []
}發送
創建一個活動,從您的餘額中扣除總金額並將訊息排隊。返回 201 狀態碼及活動信息。無法發送的號碼列在 left_out 中且不會收費。
POSThttps://smsbulk.cc/rest/v1/send
| 欄位 | 類型 | 含義 |
|---|---|---|
| to / recipients / text / default_country / opt_out | 同 Quote 中的格式。 | |
| send_at | string | ISO 8601 格式的發送時間,可設定 5 分鐘後至 90 天內。留空則立即發送。 |
| name | string | 活動標籤,最多 80 個字符。 |
| client_ref | string | 自訂參考編號,最多 64 個字符,會在每條訊息和 webhook 中返回。 |
HTTP/1.1 201 Created
{
"campaign": {
"id": "C507318264409",
"name": null,
"status": "sending",
"source": "api",
"test": false,
"recipients": 2,
"cost": "0.01240",
"refunded": "0.00000",
"net_cost": "0.01240",
"currency": "USD",
"send_at": null,
"created_at": "2026-11-07T14:02:11.000Z",
"started_at": "2026-11-07T14:02:11.000Z",
"finished_at": null,
"client_ref": "order-batch-17"
},
"messages": 2,
"left_out": []
}活動
GEThttps://smsbulk.cc/rest/v1/campaigns?limit=25&before={id}
GEThttps://smsbulk.cc/rest/v1/campaigns/{id}
GEThttps://smsbulk.cc/rest/v1/campaigns/{id}/messages?status=failed&limit=100&after={message id}
單個活動包括每個狀態的計數:排隊中、已發送、已送達、失敗和已取消。訊息列表頁面帶有 after 和 has_more;每頁最多 1,000 條。
訊息
GEThttps://smsbulk.cc/rest/v1/messages/{id}
GEThttps://smsbulk.cc/rest/v1/messages?to=%2B14155550142&status=delivered&client_ref=order-batch-17&limit=50
{
"id": "M220947781305",
"campaign": "C507318264409",
"to": "+14155550142",
"country": "US",
"segments": 1,
"encoding": "GSM-7",
"price": "0.00485",
"status": "delivered",
"reason": null,
"reason_text": null,
"refunded": false,
"client_ref": "order-batch-17",
"created_at": "2026-11-07T14:02:11.000Z",
"sent_at": "2026-11-07T14:02:12.000Z",
"finished_at": "2026-11-07T14:02:16.000Z"
}取消已排期的活動
POSThttps://smsbulk.cc/rest/v1/campaigns/{id}/cancel
在開始時間之前有效。整個費用會以一筆賬目返還到您的餘額中,活動狀態變為已取消。
Webhooks
在控制台中設置一個 endpoint URL。我們會 POST JSON 用於 message.delivered、message.failed 和 campaign.done,以及當您按下 Send test event 時的測試。每個事件帶有四個標頭,任何 10 秒內的 2xx 回應都視為已接收。
| 欄位 | 類型 | 含義 |
|---|---|---|
| Smsbulk-Event | 標頭 | 事件名稱,例如 message.delivered。 |
| Smsbulk-Delivery | 標頭 | 遞送 ID,同一事件每次重試時保持不變。 |
| Smsbulk-Timestamp | 標頭 | 此嘗試簽署時的 Unix 時間戳(秒)。 |
| Smsbulk-Signature | 標頭 | sha256= 後接 base64 編碼的 HMAC-SHA256 簽名(由時間戳、換行符和原始正文組成,使用您的 sbw_ 密鑰計算)。 |
送達嘗試 8 次:立即,然後在 1 分鐘、5 分鐘、15 分鐘、1 小時、3 小時、6 小時和 12 小時後。每次嘗試都會在控制台送達日誌中顯示其 HTTP 狀態和您的回應開頭。
{
"id": "dlv_3f9a1c07b2e44d58a6c1",
"event": "message.failed",
"created": "2026-11-07T14:02:16.000Z",
"data": {
"message": "M220947781305",
"campaign": "C507318264409",
"to": "+447400123456",
"country": "GB",
"status": "failed",
"reason": "not_in_service",
"segments": 1,
"price": "0.00755",
"client_ref": "order-batch-17"
}
}驗證簽名
import crypto from "node:crypto";
// raw = the request body exactly as received (string), secret = your sbw_ signing secret
export function verify(raw, headers, secret) {
const ts = headers["smsbulk-timestamp"];
const want = "sha256=" + crypto.createHmac("sha256", secret).update(ts + "\n" + raw).digest("base64");
const got = headers["smsbulk-signature"] || "";
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
return fresh && got.length === want.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(want));
}import base64, hashlib, hmac, time
def verify(raw: bytes, headers, secret: str) -> bool:
ts = headers.get("Smsbulk-Timestamp", "")
mac = hmac.new(secret.encode(), ts.encode() + b"\n" + raw, hashlib.sha256).digest()
want = "sha256=" + base64.b64encode(mac).decode()
fresh = abs(time.time() - int(ts or 0)) < 300
return fresh and hmac.compare_digest(want, headers.get("Smsbulk-Signature", ""))錯誤及限制
錯誤會使用 HTTP 狀態碼和 JSON 回應體: {"error":{"code":"insufficient_credit","message":"..."}}。請求失敗時不會收取任何費用。
| 欄位 | 類型 | 含義 |
|---|---|---|
| 400 bad_json | 正文非 JSON 格式。 | |
| 401 unauthorized | 密鑰缺失、格式錯誤或已被撤銷。 | |
| 402 insufficient_credit | 總額超過你的餘額。請在控制台充值。 | |
| 404 not_found | 此帳戶沒有此端點、活動、訊息或ISO代碼。 | |
| 409 not_scheduled | 已開始的活動無法取消。 | |
| 422 text_missing, text_too_long, too_many_segments | 訊息為空、超過2,000個字符,或對一個收件人超過10個分段。 | |
| 422 no_recipients, too_many, recipients_missing | 無可發送號碼、超過8,000個號碼,或既無to也無recipients。 | |
| 422 schedule_range, bad_send_at | send_at不在5分鐘到90天內,或不是有效時間。 | |
| 422 opt_out_unset | opt_out為真但設置中未保存退訂文字。 | |
| 429 rate_limited | 此密鑰每分鐘請求超過300次。 |
每個回應都會包含 X-RateLimit-Limit、X-RateLimit-Remaining 和 X-RateLimit-Reset。
排除的代碼
在計價前被移除的號碼會以 left_out 形式返回,包含其在列表中的位置、您發送的值、代碼及簡明原因。
| 欄位 | 類型 | 含義 |
|---|---|---|
| no_country_code | 無+且無默認國家。 | |
| too_short / too_long | 少於8位或多於15位數字。 | |
| not_a_number | 號碼中包含非數字字符或符號。 | |
| nanp_length | +1 號碼少於十一位數字。 | |
| not_covered | 目的地不在我們的列表中。 | |
| duplicate | 請求中重複出現相同號碼。 | |
| suppressed | 該號碼在你的禁止發送列表中。 |
狀態及原因
| 欄位 | 類型 | 含義 |
|---|---|---|
| queued | 狀態 | 等待離開我們的隊列。 |
| sent | 狀態 | 已交付網絡,等待送達報告。多數報告在幾分鐘內到達;部分網絡可能需要24小時。 |
| delivered | 狀態 | 網絡確認手機已接收。 |
| failed | 狀態 | 未送達。費用已退還至你的餘額。 |
| canceled | 狀態 | 因你取消而未發送。已退款。 |
| 欄位 | 類型 | 含義 |
|---|---|---|
| network_error | 原因 | 網絡錯誤 |
| switched_off | 原因 | 手機關機或不在服務區 |
| not_in_service | 原因 | 號碼已停用 |
| blocked | 原因 | 被網絡或收件人封鎖 |
| landline | 原因 | 固網電話或無法接收SMS的號碼 |
| content_filter | 原因 | 被網絡內容過濾器拒絕 |
| expired | 原因 | 已過期:在網絡時限前未收到報告 |
| unknown | 原因 | 未知網絡回應 |
| canceled | 原因 | 發送前已取消 |
有關 API 的疑問?請在控制台提交問題,或查閱常見問題。