• 覆盖 228 个目的地
  • 始终无需 KYC
  • 支持 Bitcoin、Monero、USDT 等 7 种币种

快速入门

五个步骤,
发送第一条消息。

从空账户开始,直到短信送达并由 Webhook 确认。只需选择一次编程语言,本页所有示例都会随之切换。

开始之前

  • 用于开设账户的电子邮箱地址
  • 终端或任意 HTTP 客户端
  • 价值几美元的加密货币,用于真实发送;测试密钥免费
  • 大约五分钟

第 1 步,共 5 步

创建账户和 API 密钥

使用电子邮箱地址注册并完成确认。在控制面板中打开开发者,然后选择创建密钥。选择 sendread 权限范围。密钥只显示一次:请将其复制到环境变量中,切勿提交到源代码管理系统。

  • 已复制密钥
  • 已导出为 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 事件。

请求GET /v1/balance
curl https://api.smsmeteor.com/v1/balance \
  -H "Authorization: Bearer $SMSMETEOR_KEY"
200 OK
{ "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
  • statusqueued;使用测试密钥时为 test
POST /v1/messages
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'];
201 Created
{
  "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。

GET /v1/messages/{id}
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'];
200 OK
{ "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.deliveredmessage.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 "", 200
import 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 秒 内响应。控制面板会列出每次尝试以及我们收到的响应;修复后可从那里重放。

后续步骤