01接口范围
六个端点覆盖完整产品。
控制面板能做的事,API 都能做;两者不存在独占功能。
| 方法 | 端点 | 功能 |
|---|---|---|
| POST | /v1/messages | 发送一条消息,返回 id、价格和初始状态。 |
| POST | /v1/messages/batch | 一次请求最多发送 1,000 条消息,每条都可使用不同文本和发送方。 |
| GET | /v1/messages/{id} | 查询一条消息的当前状态、运营商代码、时间戳和价格。 |
| GET | /v1/messages | 列出并筛选消息:状态、目的地、群发任务和日期范围。结果分页返回。 |
| GET | /v1/rates | 以 JSON 返回完整费率表,或通过 /v1/rates/{iso} 查询单个国家/地区。 |
| GET | /v1/balance | 返回 USD 余额、待确认充值和您设置的低余额阈值。 |
02消息生命周期
六种状态,每种含义都很明确。
消息状态只会向前推进。无论轮询还是监听 Webhook,都可以依赖以下顺序。
- Webhook 会推送每次状态变化;如有运营商代码,也会一并提供。
- 有效期为 48 小时。超过有效期仍未送达的消息会变为 expired。
- 计费发生在状态变为 sent 时。rejected 消息绝不收费。
- 排队中已接受并计价,正在等待路由名额。
- 已发送已交给运营商,此时计费。
- 已送达手机已确认接收。最终状态。
- 失败运营商拒绝发送或无法联系手机,并附错误代码。最终状态。
- 已过期未能在有效期内送达。最终状态。
- 已拒绝发送前被拒绝:号码无效、内容被拦截或余额为空。不计费。最终状态。
03错误
稳定的代码、易读说明,以及导致错误的字段。
所有非 2xx 响应都使用同一 JSON 结构。遇到 429 和 5xx 时重试;遇到 4xx 时修正后重新发送。
| HTTP | 代码 | 含义 | 处理方法 |
|---|---|---|---|
| 400 | invalid_number | 目的地不是有效的 E.164 号码。 | 将号码规范化;响应会指出对应字段。 |
| 401 | unauthorized | 密钥缺失、已撤销或受 IP 限制。 | 在控制面板中检查密钥和允许名单。 |
| 402 | insufficient_balance | 发送该消息会使余额低于零。 | 请充值。设置低余额 Webhook 可避免此问题。 |
| 409 | idempotency_conflict | 同一密钥被用于不同的请求负载。 | 发送新消息时使用新密钥。 |
| 422 | unsupported_destination | 没有前往该国家/地区或号段的路由。 | 在覆盖范围页面查询该目的地。 |
| 422 | sender_not_allowed | 此路由不允许字母数字发送方。 | 省略 from;系统会自动分配数字发送方。 |
| 429 | rate_limited | 超过 每个密钥每秒 50 次请求。 | 等待 Retry-After 指定的时间,或使用批量端点。 |
| 5xx | internal | 平台端错误,消息未发送。 | 使用相同的 Idempotency-Key 重试。 |
import requests
r = requests.post(
"https://api.smsmeteor.com/v1/messages/batch",
headers={"Authorization": f"Bearer {KEY}",
"Idempotency-Key": "batch-2026-09-21-01"},
json={"messages": [
{"to": "+14155550142", "from": "METEOR", "text": "订单 #4821 已发货。"},
{"to": "+447700900123", "from": "METEOR", "text": "订单 #4822 已发货。"},
]},
)
for m in r.json()["messages"]:
print(m["id"], m["status"], m["price"])
const r = await fetch("https://api.smsmeteor.com/v1/messages/batch", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMSMETEOR_KEY}`,
"Idempotency-Key": "batch-2026-09-21-01",
"Content-Type": "application/json",
},
body: JSON.stringify({ messages: [
{ to: "+14155550142", from: "METEOR", text: "订单 #4821 已发货。" },
{ to: "+447700900123", from: "METEOR", text: "订单 #4822 已发货。" },
]}),
});
const { messages } = await r.json();
$ch = curl_init("https://api.smsmeteor.com/v1/messages/batch");
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $key",
"Idempotency-Key: batch-2026-09-21-01", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode(["messages" => [
["to" => "+14155550142", "from" => "METEOR", "text" => "订单 #4821 已发货。"],
["to" => "+447700900123", "from" => "METEOR", "text" => "订单 #4822 已发货。"],
]]),
]);
$res = json_decode(curl_exec($ch), true);
body, _ := json.Marshal(map[string]any{"messages": []map[string]string{
{"to": "+14155550142", "from": "METEOR", "text": "订单 #4821 已发货。"},
{"to": "+447700900123", "from": "METEOR", "text": "订单 #4822 已发货。"},
}})
req, _ := http.NewRequest("POST", "https://api.smsmeteor.com/v1/messages/batch", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("SMSMETEOR_KEY"))
req.Header.Set("Idempotency-Key", "batch-2026-09-21-01")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
{ "batch_id": "bat_3Hq9Zr", "accepted": 2, "rejected": 0,
"total_price": "0.0214", "currency": "USD",
"messages": [ { "id": "msg_9Kd2fQ", "status": "queued", "price": "0.0084" },
{ "id": "msg_9Kd2fR", "status": "queued", "price": "0.0130" } ] }
05常见问题解答
开发者在首次请求前常问的问题。
如何获取 API 密钥?
在控制面板的“开发者”页面创建。密钥是仅显示一次的 Bearer 令牌,可授予发送、读取或两者兼有的权限,也可限制为仅允许指定 IP。您随时可以撤销或轮换密钥,余额不会受到影响。
API 与控制面板使用相同的余额和费率吗?
是。同一个账户、同一份余额、同一张费率表。通过代码发送消息的费用与费率表中该目的地显示的完全一致,也会出现在同一套报告中。
速率限制是多少?
单条发送接口的限制为 每个密钥每秒 50 次请求。批量接口每次最多接受 每次 API 请求最多 1,000 条消息,因此发送一百万条消息只需一千次请求。超过限制时,您会收到 429 响应和 Retry-After 标头。
幂等键有什么作用?
重试请求时使用相同的 Idempotency-Key,API 会返回原消息,而不会再次发送。每个账户的密钥会保留 24 小时。
如何知道消息是否已送达?
轮询 GET /v1/messages/{id},或注册 Webhook,接收带运营商代码的 message.delivered 和 message.failed 事件。只要发送量不止几条,就建议使用 Webhook。
有沙盒环境吗?
每个账户都有测试密钥。使用它发送的消息会经过验证和计价,并以 test 状态返回,但不会离开平台,也不会产生任何费用。
支持哪些编程语言?
任何能发起 HTTPS 请求的语言都可以。我们提供可直接粘贴使用的 cURL、Python、Node、PHP 和 Go 示例;如果您希望生成客户端,也可使用 OpenAPI 描述文件。
在哪里查看错误说明?
每个错误均为 JSON,包含稳定的错误代码、易读说明,以及相关时导致错误的字段。完整列表位于 API 参考文档,本页也列出了最常见的错误。