第 1 步,共 5 步
创建账户和 API 密钥
使用电子邮箱地址注册并完成确认。在控制面板中打开开发者,然后选择创建密钥。选择 send 和 read 权限范围。密钥只显示一次:请将其复制到环境变量中,切勿提交到源代码管理系统。
- 已复制密钥
- 已导出为
SMSMETEOR_KEY
# macOS、Linux
export SMSMETEOR_KEY="sk_test_4b8e...c19d"
# Windows PowerShell
$env:SMSMETEOR_KEY = "sk_test_4b8e...c19d"第 2 步,共 5 步
充值余额
使用测试密钥时可跳过此步骤。若要真实发送,请打开余额,选择一种币种,并将显示的金额发送到充值地址。网络检测到交易后,款项会显示为待处理;确认后会按美元计入余额:Tron 或 Solana 通常只需数秒,比特币需要十至六十分钟。
可通过代码查询余额,并在控制面板中设置低余额阈值,以便在群发任务因余额不足而停滞前收到 balance.low 事件。
curl https://api.smsmeteor.com/v1/balance \
-H "Authorization: Bearer $SMSMETEOR_KEY"{ "balance": "250.00", "currency": "USD",
"pending": "0.00", "low_threshold": "25.00" }第 3 步,共 5 步
发送消息
只需一次 POST:提供 E.164 格式的目标号码、发件人 ID 和文本。请始终添加 Idempotency-Key;如果网络短暂中断后重试,API 会返回原始消息,而不会再发送一条。
响应会直接告知分段数和价格。没有可用线路的目标地区会返回 422 unsupported_destination,且不会计费。
- 您收到以
msg_开头的id status为queued;使用测试密钥时为test
curl https://api.smsmeteor.com/v1/messages \
-H "Authorization: Bearer $SMSMETEOR_KEY" \
-H "Idempotency-Key: first-message-001" \
-d to="+14155550142" \
-d from="METEOR" \
-d text="Hello from SMSMeteor."import os, requests
r = requests.post(
"https://api.smsmeteor.com/v1/messages",
headers={"Authorization": f"Bearer {os.environ['SMSMETEOR_KEY']}",
"Idempotency-Key": "first-message-001"},
json={"to": "+14155550142", "from": "METEOR",
"text": "Hello from SMSMeteor."},
)
msg = r.json()
print(msg["id"], msg["status"], msg["price"])const r = await fetch("https://api.smsmeteor.com/v1/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMSMETEOR_KEY}`,
"Idempotency-Key": "first-message-001",
"Content-Type": "application/json",
},
body: JSON.stringify({ to: "+14155550142", from: "METEOR",
text: "Hello from SMSMeteor." }),
});
const msg = await r.json();
console.log(msg.id, msg.status, msg.price);$ch = curl_init('https://api.smsmeteor.com/v1/messages');
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('SMSMETEOR_KEY'),
'Idempotency-Key: first-message-001', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['to' => '+14155550142',
'from' => 'METEOR', 'text' => 'Hello from SMSMeteor.']),
]);
$msg = json_decode(curl_exec($ch), true);
echo $msg['id'], ' ', $msg['status'], ' ', $msg['price'];{
"id": "msg_9Kd2fQ",
"status": "queued",
"to": "+14155550142",
"from": "METEOR",
"segments": 1,
"encoding": "gsm7",
"price": "0.0084",
"currency": "USD",
"created_at": "2026-09-21T11:42:07Z"
}第 4 步,共 5 步
读取状态
按 ID 获取消息。状态只会向前推进:从 排队中 到 已发送,然后变为 已送达、失败 或 已过期。大多数送达会在数秒内确认;部分运营商会批量返回报告。
对于单条消息,轮询即可。数量更多时,请使用下一步中的 Webhook。
curl https://api.smsmeteor.com/v1/messages/msg_9Kd2fQ \
-H "Authorization: Bearer $SMSMETEOR_KEY"r = requests.get(
"https://api.smsmeteor.com/v1/messages/msg_9Kd2fQ",
headers={"Authorization": f"Bearer {os.environ['SMSMETEOR_KEY']}"},
)
print(r.json()["status"])const r = await fetch("https://api.smsmeteor.com/v1/messages/msg_9Kd2fQ", {
headers: { Authorization: `Bearer ${process.env.SMSMETEOR_KEY}` },
});
console.log((await r.json()).status);$ch = curl_init('https://api.smsmeteor.com/v1/messages/msg_9Kd2fQ');
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('SMSMETEOR_KEY')]]);
echo json_decode(curl_exec($ch), true)['status'];{ "id": "msg_9Kd2fQ", "status": "delivered",
"sent_at": "2026-09-21T11:42:08Z",
"delivered_at": "2026-09-21T11:42:10Z",
"carrier_code": null, "price": "0.0084" }第 5 步,共 5 步
接收 Webhook
在控制面板中依次打开开发者、Webhook、添加端点。提供一个 HTTPS URL,订阅 message.delivered 和 message.failed,然后复制端点密钥。请先验证签名,再信任载荷,并在 5 秒 内返回任意 2xx 响应。
- 端点返回 200
- 已使用原始请求体验证签名
# 向本地端点模拟发送一个已签名事件
TS=$(date +%s)
BODY='{"id":"evt_test","type":"message.delivered","data":{"message_id":"msg_9Kd2fQ"}}'
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$HOOK_SECRET" | awk '{print $2}')
curl -X POST http://localhost:3000/hooks/sms \
-H "X-Meteor-Timestamp: $TS" \
-H "X-Meteor-Signature: t=$TS,v1=$SIG" \
-H "Content-Type: application/json" -d "$BODY"import hmac, hashlib, time
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/hooks/sms")
def hook():
ts = request.headers["X-Meteor-Timestamp"]
sig = request.headers["X-Meteor-Signature"].split("v1=")[1]
mac = hmac.new(SECRET.encode(), f"{ts}.".encode() + request.data,
hashlib.sha256).hexdigest()
if abs(time.time() - int(ts)) > 300 or not hmac.compare_digest(mac, sig):
abort(400)
event = request.get_json()
print(event["type"], event["data"]["message_id"])
return "", 200import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";
const app = express();
app.post("/hooks/sms", express.raw({ type: "application/json" }), (req, res) => {
const ts = req.get("X-Meteor-Timestamp");
const sig = req.get("X-Meteor-Signature").split("v1=")[1];
const mac = createHmac("sha256", process.env.HOOK_SECRET)
.update(`${ts}.${req.body}`).digest("hex");
if (!timingSafeEqual(Buffer.from(mac), Buffer.from(sig))) return res.sendStatus(400);
const event = JSON.parse(req.body);
console.log(event.type, event.data.message_id);
res.sendStatus(200);
});$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_METEOR_TIMESTAMP'];
$sig = explode('v1=', $_SERVER['HTTP_X_METEOR_SIGNATURE'])[1];
$mac = hash_hmac('sha256', $ts . '.' . $raw, getenv('HOOK_SECRET'));
if (abs(time() - (int) $ts) > 300 || !hash_equals($mac, $sig)) { http_response_code(400); exit; }
$event = json_decode($raw, true);
error_log($event['type'] . ' ' . $event['data']['message_id']);
http_response_code(200);{ "id": "evt_4Qm8Xz", "type": "message.delivered",
"created_at": "2026-09-21T11:42:10Z",
"data": { "message_id": "msg_9Kd2fQ", "status": "delivered",
"to": "+14155550142", "price": "0.0084" } }故障排除
401 unauthorized
请求头必须写为 Authorization: Bearer sk_…,密钥两侧不能加引号。请检查密钥是否已被撤销、是否具有 send 权限范围;若设置了 IP 允许列表,还要确认您的 IP 在其中。
402 insufficient_balance
可用余额低于消息价格。集成期间请使用测试密钥,或为账户充值;显示为待处理的充值暂时无法使用。
400 invalid_number
号码必须采用 E.164 格式:加号、国家代码、去掉国内长途冠码 0 的本地号码,且不能包含空格。应使用 +447700900123,而不是 07700 900123。
消息一直停留在 sent
部分运营商会批量返回送达报告,或完全不返回;国家/地区页面会注明具体情况。经过 48 小时 仍无送达报告时,消息会变为 expired。
收件人看到的是号码,而不是我的名称
目标地区不支持字母数字发件人,或要求预先注册。消息的 from 字段会显示实际使用的发件人。请参阅发件人 ID 和线路。
我的 Webhook 从未触发
端点必须使用 HTTPS 和有效证书,并在 5 秒 内响应。控制面板会列出每次尝试以及我们收到的响应;修复后可从那里重放。