用于从您自己的代码发送短信的API文档

一个与工作台使用相同账户、价格和余额的小型REST API:发送一条消息或最多5,000个号码的批量消息,首先估算成本,跟踪每条消息并在您的Webhook URL上获取送达事件。

基础 URL: https://sendsmsonline.cc/api/v1

快速开始

  1. 1. 创建密钥。 在工作台中打开 API 和 webhooks。密钥在首次充值后可用;每个密钥只显示一次,因此请复制或保存为文本文件。
  2. 2. 检查费用。 将相同的主体 POST 到 /costs 以查看收件人、分段和总费用,无需发送。
  3. 3. 发送。 将其 POST 到 /sends。响应中会包含发送 ID;消息会立即发出或在 send_at 时间发出。
curl https://sendsmsonline.cc/api/v1/sends \
  -H "Authorization: Bearer $SSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "recipients": [ { "to": "+447700900461", "fields": { "first_name": "Tom" } }, { "to": "+12015550142", "fields": { "first_name": "Ava" } } ], "text": "Hi {{first_name}}, your table is ready at 7:30.", "name": "Friday bookings", "client_ref": "bookings-1107" }'

认证

在 Authorization 标头中发送您的密钥:Authorization: Bearer sso_live_...。密钥为 49 个字符,以 sso_live_ 开头。每个账户最多 5 个密钥;在工作台中撤销一个密钥后,它将立即停止工作。价格列表是公开的,不需要密钥。

错误

错误使用 HTTP 状态代码和带有稳定代码的 JSON 主体,您可以向用户显示该句子。请求失败时不收取任何费用。

HTTP/1.1 402 Payment Required
{ "error": { "code": "insufficient_credit", "message": "Short by $3.20. Add funds to send.", "total": "8.62480", "credit": "5.42000" } }
字段含义
400请求需要修改。
401缺少、错误或已撤销的密钥。
402余额不足以支付总费用。
404没有此类发送、消息、国家或端点。
409发送已开始。
429每分钟超过240次请求。

限制

  • 每个密钥每分钟240次请求,显示在X-RateLimit-Limit、X-RateLimit-Remaining和X-RateLimit-Reset(Unix秒)中。
  • 每次请求5,000个号码,每条短信2,000个字符,每条消息10个分段。
  • 每个账户每分钟最多发送300条消息。
  • send_at从10分钟到30天前。

价格

GET/api/v1/prices

GET/api/v1/prices/{country}

每条消息(一个分段)的价格,适用于每个国家,以美元为单位,保留5位小数。无需密钥。

{ "price": { "country": "GB", "name": "United Kingdom", "dial_code": "+44", "price_usd": "0.00868" }, "updated": "2026-11-07" }

账户余额

GET/api/v1/account

{ "account": "SO8K2M4Q7X9TBA", "credit_usd": "41.27660", "currency": "USD" }

估算费用

POST/api/v1/costs

使用与发送相同的正文并返回其成本,而不实际发送或收费。每个收件人自己的合并文本决定其分段,因此总成本是准确的。

{
  "recipients": 2, "segments_min": 1, "segments_max": 1, "encoding": "gsm7", "messages_billed": 2,
  "total_usd": "0.01426", "credit_usd": "41.27660", "enough_credit": true,
  "countries": [ { "country": "GB", "recipients": 1, "price_usd": "0.00868", "subtotal_usd": "0.00868" },
                 { "country": "US", "recipients": 1, "price_usd": "0.00558", "subtotal_usd": "0.00558" } ],
  "dropped": [], "too_long": null
}

创建发送

POST/api/v1/sends

一条短信发送给一个或多个号码。整个发送的余额在发送被接受时扣除;失败的消息将逐一退款。

字段含义
to国际格式的号码(+447700900461)。使用此格式或收件人。
recipients包含to和fields的对象,用于合并字段:{ "to": "+1...", "fields": { "first_name": "Ava" } }。
text消息,最多2,000个字符。{{field}}将根据每个收件人替换;缺失的值将变为空。
send_at可选的ISO 8601时间,带偏移量或Z。如果没有,发送将立即开始。
name在工作台中显示的可选标签(80个字符)。
client_ref在webhooks中返回的可选参考(64个字符)。
opt_out将保存在设置中的退订行添加到文本末尾。
default_country用于没有国家代码的号码的ISO代码。
HTTP/1.1 201 Created
{
  "send": { "id": "CA7Q29XMAB4DFK", "status": "queued", "source": "api", "recipients": 2, "segments_max": 1,
            "encoding": "gsm7", "cost_usd": "0.01426", "refunded_usd": "0.00000", "client_ref": "bookings-1107",
            "send_at": null, "created_at": "2026-11-07T10:12:03.120Z", "started_at": null, "finished_at": null },
  "dropped": [ { "value": "+4412", "code": "too_short", "message": "Too short" } ]
}

无法发送的号码列在dropped中,且不会被收费。代码:no_country_code, too_short, too_long, not_a_number, wrong_length, not_covered, duplicate和suppressed(在您的禁止发送列表中)。

获取或列出发送

GET/api/v1/sends/{id}

GET/api/v1/sends?limit=25&before={id}

一次发送包括每个消息状态的counts。列表按最新优先;将next_before作为before传递以获取下一页。来自工作台的发送也会出现在这里,带有source: "web"。

消息

GET/api/v1/sends/{id}/messages?status=failed&limit=100

GET/api/v1/messages/{id}

{ "message": { "id": "MS3D8RW0K2QJ7N", "send_id": "CA7Q29XMAB4DFK", "to": "+447700900461", "country": "GB",
  "segments": 1, "price_usd": "0.00868", "status": "delivered", "reason": null, "reason_text": null,
  "created_at": "2026-11-07T10:12:03.120Z", "sent_at": "2026-11-07T10:12:04.010Z", "done_at": "2026-11-07T10:12:09.400Z" } }

取消发送

POST/api/v1/sends/{id}/cancel

只有尚未开始的预定发送可以取消。全额费用将返回到您的余额中,并且答案包括refunded_usd。

Webhooks

在工作台(API和webhooks)中设置一个https URL。当消息送达或失败时,我们会POST一个事件,适用于来自API和工作台的发送。在10秒内以任何2xx状态响应。失败的投递最多会重试7次:立即重试,然后在1分钟、5分钟、30分钟、1小时、2小时和3小时后重试。工作台显示每次尝试的状态和响应。

POST https://your-server.example/sms-events
X-SSO-Event: message.delivered
X-SSO-Delivery: evt_5a0c9e31d2b7f4a68c
X-SSO-Timestamp: 1794132729
X-SSO-Signature: sha256=8f1c...e42a

{ "id": "evt_5a0c9e31d2b7f4a68c", "event": "message.delivered", "created": "2026-11-07T10:12:09.000Z",
  "data": { "message": { "id": "MS3D8RW0K2QJ7N", "send_id": "CA7Q29XMAB4DFK", "to": "+447700900461", "country": "GB",
  "segments": 1, "price_usd": "0.00868", "status": "delivered", "reason": null, "reason_text": null,
  "client_ref": "bookings-1107", "created_at": "...", "sent_at": "...", "done_at": "..." } } }

签名是HMAC-SHA256的timestamp + "." + raw body与您的签名密钥(以sso_whk_开头)。在解析前检查原始正文,拒绝超过5分钟的时间戳,并使用投递ID忽略重复。

import crypto from "node:crypto";

// rawBody: the request body exactly as received (a string), before JSON.parse
export function verify(rawBody, headers, secret) {
  const ts = headers["x-sso-timestamp"];
  const sig = headers["x-sso-signature"] || "";
  const want = "sha256=" + crypto.createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return fresh && sig.length === want.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(want));
}

事件类型:message.delivered(消息已送达)、message.failed(消息发送失败)以及通过“发送测试事件”按钮触发的test(测试)。

状态和原因

字段含义
queued等待离开我们的队列。
sent已提交至网络,等待发送报告。大多数报告在几分钟内到达;部分网络可能需要长达24小时。
delivered网络确认手机已接收。
failed未送达。费用已退还至您的余额。
canceled因您取消而未发送。已退款。

失败原因(reason字段):

字段含义
network_error网络错误
absent手机关机或不在服务区
not_in_service号码已停用
blocked被网络或收件人屏蔽
landline固话或无法接收短信的号码
content_filter被网络内容过滤器拒绝
expired已过期:在网络时限内未收到报告
canceled发送前取消
unknown未知网络响应

服务检查在状态页,API变更在更新日志。

获取您的API密钥

创建一个账户,充值一次并在工作台中启用API和Webhooks。同一个密钥适用于所有国家。

创建免费账户
短信API文档:从代码中发送批量短信 | SendSMSOnline