給工程師的 SMS API。
REST + JSON · x-api-key 認證 · 兩段式 DLR callback
一個 POST 送出訊息,兩次 callback 告訴你「提交了」與「送到了」 —
這兩件事我們分開回報,因為它們本來就不是同一回事。
香港 OFCA Sender ID、拒收登記冊過濾、跨區欄位差異,這頁全部寫清楚。
找的是產品面說明?請看 SMS 服務頁 — 100+ 香港證券行採用、雙路由 failover、# Sender ID 代辦。
POST /v1/sms/send
x-api-key: YOUR_API_KEY
{
"sender": "XLEAD",
"country_code": "852",
"mobile": "91234567",
"content": "閣下的登入驗證碼為 482910"
}
→ { "rc": 100, "ref_id": "145737475" }
→ callback 1: "status": "SMD"
→ callback 2: "status": "DELIVRD" 一個 POST,第一條 SMS 就送出去
不用 SDK、不用 OAuth 流程。取得 API key 後貼上下面這段,改掉號碼就能跑。
- 1
取得 API Key
登入 X Lead 後台建立 API key。之後每個請求都在 header 帶上 x-api-key。
- 2
呼叫 send endpoint
POST 一個 JSON,一個請求對應一位收件人。回應立即帶回 ref_id。
- 3
接收 callback
在後台設定 Callback URL,我們把提交結果與電信商送達回報推回你的系統。
送出一條香港 SMS
curl -X POST https://api.connect.xleadfunnel.com/v1/sms/send \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"sender": "XLEAD",
"country_code": "852",
"mobile": "91234567",
"content": "閣下的登入驗證碼為 482910",
"send_also_ofca_registrants": false
}' 同步回應
{
"rc": 100,
"rm": "OK",
"ref_id": "145737475"
} ref_id 是這次請求的識別碼 — 之後兩次 callback 都會帶同一個 ref_id,用它對帳。
認證、端點與參數
一個 header 完成認證;三個端點覆蓋整條發送鏈:送出、查用量、查餘額。
認證
- Base URL
https://api.connect.xleadfunnel.com- 認證方式
Header:x-api-key: YOUR_API_KEY- 編碼
UTF-8- 請求格式
application/json(POST)
端點
- POST
/v1/sms/send送出一條 SMS,一個請求對應一位收件人。 - GET
/v1/sms/get-usage-report以日期區間查詢用量彙總(date_from / date_to,YYYY-MM-DD)。 - GET
/v1/acct/get-points-balance查詢剩餘點數餘額。SMS 與 MMS 共用同一池點數。
POST /v1/sms/send 參數
| 參數 | 型別 | 必填 | 說明 |
|---|---|---|---|
country_code | string | 必填 | 地區號碼,1–3 位數字,不含前置 0。香港為 852。 |
mobile | string | 必填 | 收件人號碼,最多 10 位數字,可帶前置 0。 |
content | string | 選填 | 訊息內容,UTF-8。 |
sender | string | 選填 | 發送人名稱,3–11 位英數字。發往香港必須提供已登記的 Sender ID;發往台灣則不需要此欄位。 |
send_also_ofca_registrants | boolean | 選填 | 預設 false — 不發送給已登入 OFCA 拒收訊息登記冊的號碼。僅適用於香港。 |
回應欄位
| 參數 | 型別 | 說明 |
|---|---|---|
rc | integer | 100 = OK;-100 = 輸入無效 |
rm | string | 回應訊息,失敗時帶原因說明 |
ref_id | string | 本次請求的識別碼,後續 callback 會帶同一個值 |
地區差異:一個欄位的分別
sender 這個欄位是否必填,由收件地區的法規決定 — 這也是為什麼跨區發送不能只寫一套 payload。
必須提供已登記的 Sender ID,否則請求會被拒。另可用 send_also_ofca_registrants 控制是否略過 OFCA 拒收登記冊。
不需提供 sender 欄位。省略即可,帶了反而可能造成驗證失敗。
兩段式回報 — 提交結果,然後才是送達結果
「已提交」不等於「已送達」。我們把兩件事分成兩次 callback,讓你分得清楚是自己的資料有問題,還是電信商那端沒送到。
你需要先登入後台設定 Callback URL,才會收到這些回報。
Callback 內容格式
rc- 回應碼
rm- 回應訊息,如有則附詳細說明
ref_id- 原本 API 呼叫時回傳的 reference id
status- 本次請求的提交或送達狀態
Callback 範例
// 第一段 — 已提交電信商,本則扣點
{ "rc": 100, "rm": "OK", "ref_id": "145737475", "status": "SMD" }
// 第一段 — 驗證失敗,不扣點
{ "rc": -100, "rm": "...", "ref_id": "145737476", "status": "IM" }
// 第二段 — 電信商回報最終送達狀態
{ "rc": 100, "rm": "OK", "ref_id": "145737475", "status": "DELIVRD" } 第一段 · 送出請求回報
你的請求是否通過驗證並提交給電信商。這一段決定是否扣點。
rc = 100 會扣點 SMD- 有效發送,訊息已提交電信商等待派送
rc = -100 不扣點 IM- 地區號碼或手機號碼不正確
OFCA- 號碼在 OFCA 拒收訊息登記冊中,已被過濾(僅香港)
IUL- 號碼在拒收名單(unsend list)中,未發送
IP- 點數不足
IS- 無效的發送人名稱,或該 Sender ID 未在你的帳戶登記
第二段 · 送達回報(DLR)
電信商回傳收件人裝置的最終狀態時,我們原樣轉給你。
rc = 100DELIVRD- 電信商已成功送達收件人裝置
EXPIRED- 處理超過有效期,未能送達
UNDELIV- 無法送達 — 目的地不可達、網絡問題,或收件人裝置關機
REJECTD- 被拒 — 內容無效、列入黑名單,或政策限制
UNKNWN- 電信商無法判定訊息的最終送達狀態
為什麼我們把失敗碼全部列出來
有些供應商只回「submitted」就當成功,帳單照收。我們把提交與送達拆成兩段、把每個失敗碼原樣轉給你,是因為你需要能對帳:收多少筆、提交多少筆、真正送達多少筆,三個數字都要對得上。
了解誠實送達 →用你手上的語言接進去
同一個 POST,六種寫法。全部只依賴各語言的標準 HTTP 用戶端 — 不需要安裝我們的 SDK。
cURL
curl -X POST https://api.connect.xleadfunnel.com/v1/sms/send \
-H "Content-Type: application/json" \
-H "x-api-key: $XLEAD_API_KEY" \
-d '{
"sender": "XLEAD",
"country_code": "852",
"mobile": "91234567",
"content": "閣下的登入驗證碼為 482910"
}' Node.js
const res = await fetch('https://api.connect.xleadfunnel.com/v1/sms/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.XLEAD_API_KEY,
},
body: JSON.stringify({
sender: 'XLEAD',
country_code: '852',
mobile: '91234567',
content: '閣下的登入驗證碼為 482910',
}),
});
const { rc, rm, ref_id } = await res.json();
if (rc !== 100) throw new Error(`send failed: ${rm}`);
console.log('queued as', ref_id); Python
import os, requests
res = requests.post(
'https://api.connect.xleadfunnel.com/v1/sms/send',
headers={'x-api-key': os.environ['XLEAD_API_KEY']},
json={
'sender': 'XLEAD',
'country_code': '852',
'mobile': '91234567',
'content': '閣下的登入驗證碼為 482910',
},
timeout=10,
)
data = res.json()
if data['rc'] != 100:
raise RuntimeError(f"send failed: {data['rm']}")
print('queued as', data['ref_id']) PHP
<?php
$ch = curl_init('https://api.connect.xleadfunnel.com/v1/sms/send');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-api-key: ' . getenv('XLEAD_API_KEY'),
],
CURLOPT_POSTFIELDS => json_encode([
'sender' => 'XLEAD',
'country_code' => '852',
'mobile' => '91234567',
'content' => '閣下的登入驗證碼為 482910',
], JSON_UNESCAPED_UNICODE),
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($data['rc'] !== 100) {
throw new RuntimeException('send failed: ' . $data['rm']);
}
echo 'queued as ' . $data['ref_id']; Java
var body = """
{"sender":"XLEAD","country_code":"852",
"mobile":"91234567","content":"閣下的登入驗證碼為 482910"}
""";
var req = HttpRequest.newBuilder()
.uri(URI.create("https://api.connect.xleadfunnel.com/v1/sms/send"))
.header("Content-Type", "application/json")
.header("x-api-key", System.getenv("XLEAD_API_KEY"))
.POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
.build();
var res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
System.out.println(res.body()); // {"rc":100,"rm":"OK","ref_id":"..."} C# / .NET
using var http = new HttpClient();
http.DefaultRequestHeaders.Add(
"x-api-key", Environment.GetEnvironmentVariable("XLEAD_API_KEY"));
var payload = new {
sender = "XLEAD",
country_code = "852",
mobile = "91234567",
content = "閣下的登入驗證碼為 482910"
};
var res = await http.PostAsJsonAsync("https://api.connect.xleadfunnel.com/v1/sms/send", payload);
var data = await res.Content.ReadFromJsonAsync<JsonElement>();
if (data.GetProperty("rc").GetInt32() != 100)
throw new Exception(data.GetProperty("rm").GetString()); 正式環境請把 API key 放進環境變數,不要寫死在程式碼裡。
從開戶到上線,3 個步驟
不需要先簽長約才能試。多數客戶第一週就把測試發送跑通,Sender ID 登記在背景同步進行。
- 1
開立帳戶
聯絡我們說明用途與預估量,我們開好帳戶並配置適合你收件地區的路由。
- 2
建立 API key
在後台產生 key,之後每個請求以 header 帶上 x-api-key。只放伺服器端。
- 3
3 分鐘設定 API 並測試
先在後台一鍵發一則測試短訊確認路由與顯示,再照上方 Quickstart 用 API 發出第一則訊息 — 前後約 3 分鐘。
跑通之後,再補上
- +
設定 Callback URL(可選)
需要接收兩段式 DLR 回報時,在後台填入你的 endpoint — 沒設定就收不到任何 DLR。
- +
登記 # Sender ID(建立品牌)
發往香港需要已登記的發送人名稱,也是收件匣裡的品牌識別。命名檢核、文件、安全網絡我們代辦,可與整合並行。
整合常見問題
一個請求可以發給多位收件人嗎? +
不行。/v1/sms/send 是一個請求對應一位收件人。要群發就在你這邊迴圈呼叫,每一筆都會拿到自己的 ref_id,對帳與重送都以單筆為單位。若你要的是大批量排程廣播,後台的發送介面比自己寫迴圈更合適。
rc = 100 是不是代表客戶已經收到? +
不是。同步回應的 rc = 100 只代表我們收下並排入佇列。真正的提交結果在第一段 callback(status = SMD 才是已提交電信商),最終是否送到收件人裝置要看第二段 callback 的 DELIVRD。把這三件事混為一談,是自建報表最常見的錯誤。
為什麼發往香港一定要 sender,發往台灣卻不用? +
因為規範不同。香港 OFCA 實施短訊發送人登記制,商業訊息必須使用已登記的發送人名稱,所以 sender 必填且必須是你帳戶下已登記的 Sender ID;台灣不採這套制度,該欄位不需提供。跨區發送時請依收件地區組裝 payload。
send_also_ofca_registrants 應該設什麼? +
預設 false,代表不發送給已登入 OFCA 拒收訊息登記冊的號碼 — 推廣訊息應維持這個預設。只有在該訊息屬於登記冊規管範圍以外的情況(例如收件人與你之間已有既存關係下的交易類通知),才需要考慮改成 true,而責任在發送方。不確定就保持 false。
收不到 callback,要檢查什麼? +
依序檢查:後台是否已設定 Callback URL;該 URL 是否對外可達且回應 2xx;是否走 HTTPS 且憑證有效;有沒有被防火牆擋掉。另外請把 callback 處理寫成冪等的 — 以 ref_id + status 作為唯一鍵,重複收到同一則不應該重複扣庫存或重複發信。
DELIVRD 以外的狀態要怎麼處理? +
UNDELIV 多半是關機或不在服務範圍,可以稍後重試;EXPIRED 代表在有效期內一直送不到,重試前先確認號碼仍在使用;REJECTD 是內容或政策問題,重送同樣內容只會再被拒,要先改內容或查發送人設定;UNKNWN 是電信商無法判定,不宜當成失敗直接重發,建議先累積觀察比例。
怎麼對帳? +
用 ref_id 串起三個點:你送出的請求數、第一段 callback 回 SMD 的筆數(這是計費基準)、第二段 callback 回 DELIVRD 的筆數。另外可用 /v1/sms/get-usage-report 以日期區間取回 sms_count 與 points_used,跟你自己的紀錄互相驗證。
有沒有測試環境? +
開戶後即可在後台一鍵測試發送,管理員不必先寫程式就能確認 Sender ID 與路由設定正確。需要以 API 進行整合測試,聯絡我們索取測試用 API key 與少量測試點數。