大量簡訊 API 文件

BulkSMSOnline REST API 讓您從自己的軟體發送簡訊至 227 個國家,價格、分段規則、排程與退款都與主控台相同。請求與回應皆為透過 HTTPS 傳輸的 JSON,每個最終傳送狀態都可以用簽章 Webhook 推送到您的伺服器。

基礎 URLhttps://bulksmsonline.cc/api/v1

概覽

當訊息由您自己的系統觸發時使用 API:商店的訂單更新、登入表單的驗證碼、預約工具的提醒。對 POST /v1/messages 發出最多 10,000 個號碼的請求,會建立一個活動、扣除餘額並將每則訊息排入佇列。透過 API 建立的活動也會連同傳送報告出現在主控台中。

  • 所有金額皆為美元,以五位小數的字串表示,例如 "0.00534"。
  • 電話號碼採國際格式,開頭的 + 可有可無;空格與連字號會被移除。
  • 時間為 UTC 的 ISO 8601,例如 2026-12-01T09:00:00Z。
  • 訊息與活動的 id 形如 MSG-XXXX-XXXX-XXXX 與 CMP-XXXX-XXXX-XXXX。

驗證

在主控台的 API 下建立 API 金鑰(金鑰在您的首次儲值入帳後開通)。每次請求都要在 Authorization 標頭中傳送它。金鑰形如 bso_api_ 後面接 36 個字元;它只會顯示一次,請作為機密存放在您的伺服器上。建立新金鑰會立即取代前一把。

Authorization: Bearer bso_api_0123456789abcdef0123456789abcdef0123
Content-Type: application/json

限制

請求每把金鑰每分鐘 300 次;超過會回應 429 rate_limited
每次請求的號碼數10,000
訊息內容照寫的 2,000 個字元,最多 10 個分段
排程send_at 為 5 分鐘後到 60 天內
發送速度每個佇列每分鐘 400 則訊息
Webhook 重試約 22 小時內共 9 次嘗試

發送訊息

POST/v1/messages

將一則內容發送到一個或多個號碼。請求被接受時,會從餘額扣除全額費用;無法送達的每則訊息之後會退款。回應狀態為 201,並附上活動及其每則訊息。

欄位說明
to必填一個號碼,或最多 10,000 個國際格式號碼的陣列。重複的號碼只發送一次;無法讀取的會列在 skipped 中。
text必填訊息,最多 2,000 個字元與 10 個分段。GSM-7 文字每則 SMS 容納 160 個字元,Unicode 為 70 個。
send_at選填用於排程發送的 ISO 8601 時間,為 5 分鐘後到 60 天內。省略則立即發送。
opt_out選填true 會在結尾換行加入主控台設定中的退訂提示。
client_ref選填您自己的參考值,最多 64 個字母、數字與_ . : -。它會在報告與 Webhook 中回傳。
curl -X POST https://bulksmsonline.cc/api/v1/messages \
  -H "Authorization: Bearer $BSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":["+447700900412","+33612345678"],"text":"Order 4521 has shipped. Track it at shop.example/t/4521","client_ref":"order-4521"}'
HTTP/1.1 201 Created
{
  "id": "CMP-7KQ2-M9XA-4HTD",
  "status": "sending",
  "channel": "api",
  "recipients": 2,
  "segments": 1,
  "encoding": "GSM-7",
  "cost": "0.02158",
  "refunded": "0.00000",
  "client_ref": "order-4521",
  "send_at": null,
  "counts": { "queued": 2, "submitted": 0, "delivered": 0, "failed": 0, "canceled": 0 },
  "skipped": [],
  "balance": "118.43120",
  "messages": [
    { "id": "MSG-3RTW-81KD-ZQ0P", "to": "+447700900412", "country": "GB", "segments": 1, "price": "0.00834", "status": "queued" },
    { "id": "MSG-5HNA-4C2E-7YVB", "to": "+33612345678", "country": "FR", "segments": 1, "price": "0.01324", "status": "queued" }
  ]
}

發送報價

POST/v1/quote

接受與 /v1/messages 相同的內容,並在不發送、不扣款的情況下回傳精確費用、分段數與編碼。可用於在您自己的使用者確認前向他們顯示價格。

{
  "recipients": 2,
  "skipped": [],
  "segments": 1,
  "encoding": "GSM-7",
  "cost": "0.02158",
  "balance": "118.45278",
  "countries": [ { "country": "GB", "recipients": 1, "cost": "0.00834" }, { "country": "FR", "recipients": 1, "cost": "0.01324" } ]
}

餘額

GET/v1/balance

{ "balance": "118.43120", "currency": "USD" }

費率

GET/v1/rates

GET/v1/rates/{country}

每個目的地,或單一兩字母 ISO 國碼的每個 SMS 分段價格。這兩個端點是公開的,不需要金鑰。

{ "country": "DE", "name": "Germany", "calling_code": "+49", "price": "0.01544", "currency": "USD", "per": "segment" }

訊息狀態

GET/v1/messages/{id}

{
  "id": "MSG-3RTW-81KD-ZQ0P",
  "campaign_id": "CMP-7KQ2-M9XA-4HTD",
  "to": "+447700900412",
  "country": "GB",
  "segments": 1,
  "price": "0.00834",
  "status": "delivered",
  "error": null,
  "created_at": "2026-11-07T09:00:02Z",
  "submitted_at": "2026-11-07T09:00:03Z",
  "final_at": "2026-11-07T09:00:08Z"
}

活動

GET/v1/campaigns/{id}

GET/v1/campaigns/{id}/messages?offset=0&limit=100

第一個回傳活動及其各狀態的數量;第二個分頁列出其訊息,每頁最多 1,000 則。從主控台發送的活動也可用其頁面上顯示的 id 以相同方式讀取。

取消排定的發送

POST/v1/campaigns/{id}/cancel

停止以 send_at 建立且尚未開始的活動。每則訊息都會被取消,全額費用退回餘額。已在發送中的活動會回應 409 not_scheduled。

傳送回報 Webhook

在主控台的 API 下新增 HTTPS URL,以 POST 請求接收每個最終狀態(delivered 或 failed)。請在 8 秒內以任何 2xx 狀態回應。其他回應與逾時會在 20 秒、1 分鐘、5 分鐘與 15 分鐘後重試,然後是 1、3、6 與 12 小時,共 9 次嘗試。同一事件可能到達兩次,因此請用 event_id 確保只處理一次。

POST https://your-server.example/sms-status
Content-Type: application/json
X-BulkSMSOnline-Signature: t=1794042008,v1=5f0c2a...e91b

{
  "type": "message.status",
  "event_id": "ev_8f1c22d0a4b97e63c1f0",
  "sent_at": "2026-11-07T09:00:09Z",
  "data": {
    "message_id": "MSG-3RTW-81KD-ZQ0P",
    "campaign_id": "CMP-7KQ2-M9XA-4HTD",
    "to": "+447700900412",
    "country": "GB",
    "status": "delivered",
    "error": null,
    "segments": 1,
    "price": "0.00834",
    "currency": "USD",
    "client_ref": "order-4521",
    "final_at": "2026-11-07T09:00:08Z"
  }
}

驗證簽章

標頭包含 Unix 時間 t 與簽章 v1,v1 是以您的 Webhook 密鑰對字串 "t.raw_body" 計算的 HMAC-SHA256,採十六進位。請在解析 JSON 之前對原始內容計算,以固定時間比對,並拒絕超過五分鐘的事件。

import crypto from "node:crypto";

export function verify(rawBody, 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 = crypto.createHmac("sha256", secret).update(m[1] + "." + rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(want), Buffer.from(m[2]));
}

狀態

queued已接受,等待離開佇列
submitted已交給目的地網路
delivered手機已確認(最終)
failed無法送達;費用已退款(最終)
canceled排定活動的一部分,在發送前被取消(最終)

活動狀態為 scheduled、sending、complete 或 canceled。

錯誤

錯誤會回應 HTTP 狀態與 JSON 內容:{ "error": { "code": "insufficient_balance", "message": "..." } }。請求回應錯誤時不會扣款。

HTTP代碼意義
400invalid_request欄位缺少或無效;訊息會說明是哪一個。
400invalid_json內容不是 JSON。
400no_valid_numbers沒有任何號碼可以讀取。
401unauthorized金鑰缺少、格式不正確或已被取代。
402insufficient_balance餘額不足以支付費用;請儲值後再發送。
404not_found未知的 id 或端點。
409not_scheduled只有尚未開始的排定活動可以取消。
413too_many_recipients單次請求超過 10,000 個號碼。
429rate_limited一分鐘內超過 300 次請求。
500server_error請重試請求;未扣任何款項。

在主控台取得 API 金鑰

建立帳戶、完成首次儲值,然後在 API 下產生金鑰。一分鐘後即可送出您的第一個請求。

建立帳戶
大量簡訊 API 文件:REST 端點與 Webhook | BulkSMSOnline