开发者
API 文档
在您自己的代码中读取余额,以及任意国家、任意服务的实时价格。一个持有者密钥,JSON over HTTPS,无需安装 SDK。
快速入门 #
全部采用 HTTPS 上的 JSON,用您自己创建的一个密钥完成鉴权。无需安装 SDK,无需签署合同,无需申请沙盒—一个密钥加 curl 即可。
- 1 创建密钥 打开账户菜单,选择 API 密钥,再选择创建密钥。密钥只显示一次:我们只保存其指纹,之后无法再次查看。
- 2 发送 Bearer 令牌 每个请求都携带 Authorization 请求头。没有其他接入方式—密钥不能出现在查询字符串中,不用 cookie,也不用 session。
- 3 读取响应 每个响应都是包含 ok 字段的 JSON 对象。当 ok 为 false 时,error 字段会用一个稳定、可供程序读取的字符串说明原因。
鉴权 #
每个账户只有一个密钥。除了下方的请求头方式外,其他发送方式均不支持—密钥若出现在查询字符串中,会被记录进服务器日志、浏览器历史和 referrer 请求头,因此会被直接拒绝,而不是悄悄接受。
Authorization: Bearer sk_your_key_here
密钥可用于消费 如今它能读取余额,将来订购号码功能上线后,用的也是同一个密钥。请像对待密码一样对待它:不要放进源代码仓库,不要出现在截图里,要替换而不是分享。替换密钥会立即关闭旧密钥。
约定 #
| 基础地址 | https://simsms.com/api/v1 |
|---|---|
| 传输方式 | 仅支持 HTTPS。普通 HTTP 会被重定向,且重定向请求不会携带您的请求头。 |
| 格式 | 输入输出均为 JSON。每个响应都是对象,绝不是裸数组。 |
| 成功 | HTTP 200,返回 "ok": true。 |
| 失败 | 4xx 或 5xx 状态码,返回 "ok": false,以及一个稳定的 "error" 字符串。 |
| 金额 | 金额以美元数字表示,绝不是字符串,也绝不是美分。0.84 表示 84 美分。 |
| 未知字段 | 任何响应都可能新增字段。遇到不认识的字段请忽略,而不是报错。 |
错误 #
用于程序判断分支的是 error 字符串。旁边的说明句是写给您看的,不是给代码用的—说明句可能会改写,但字符串不会。
| HTTP | 错误 | 何时 |
|---|---|---|
| 401 | missing_key |
没有 Authorization 请求头,或者它不是 Bearer 令牌。 |
| 401 | bad_key |
密钥未知,或者已被关闭或替换。 |
| 400 | unknown_service |
没有该代码对应的服务。代码来自目录,而不是显示名称。 |
| 404 | no_stock |
该服务与国家的组合目前没有库存号码。这是实时数据—库存可能会恢复。 |
| 404 | unknown_country |
该产品没有该代码对应的国家。代理和租用目录各自有自己的国家列表—不带国家参数调用该接口即可获取。 |
| 400 | unknown_tech |
该国家没有这一代网络。只有美国同时提供 4g 和 5g。 |
| 429 | rate_limited |
请求过于频繁。Retry-After 请求头会说明需要等待多少秒。 |
速率限制 #
每分钟 600 次请求,按账户而非按地址计数。密钥本应运行在服务器上—单一地址—因此按地址限制会误伤正常使用,还会让被盗的密钥在别处畅通无阻。超过限制会返回 429,并附带以秒为单位的 Retry-After 请求头。
接口 #
账户与目录的读取接口。每个路由都列出其全部参数、返回的全部字段,以及可能返回的全部错误——没有未文档化的行为。
查询余额 #
GET
/api/v1/balance
账户当前持有的金额,以及按目录中当前最低价格能买到多少条验证码。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
ok |
boolean | 在 200 响应中始终为 true。 |
balance |
number | 可用余额(美元),精确到美分。 |
currency |
string | 始终是 "USD",让您不必自行假设币种。 |
codes_at_cheapest |
integer | 按目录最低价格计算,余额能买到多少条验证码。这只是粗略参考,不是报价—目录为空时为 null。 |
cheapest_code |
number | 该最低价格,方便您用其他数值自行计算这个参考值。 |
请求
curl -s "https://simsms.com/api/v1/balance" \
-H "Authorization: Bearer $SIMSMS_KEY"
响应
{
"ok": true,
"balance": 42.5,
"currency": "USD",
"codes_at_cheapest": 425,
"cheapest_code": 0.1
}
单个国家的服务价格 #
GET
/api/v1/pricing?service={service}&country={country}
针对单一组合的实时价格与实时库存。两个数字都会变动—价格取决于该国家承载该服务的最低价网络,库存则是网络实时上报的数值。
参数
| 参数 | 说明 | |
|---|---|---|
service |
必填 | 服务代码,例如 telegram。小写,来自目录。 |
country |
可选 | 国家代码,例如 england。不填则一次获取所有国家—见下文。 |
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
ok |
boolean | 在 200 响应中始终为 true。 |
service |
string | 您所请求的服务代码,原样返回。 |
country |
string | 您所请求的国家代码,原样返回。 |
price |
number | 以最低价网络计算,一条验证码的美元价格。 |
stock |
integer | 当前上报的可用号码数量。这是实时数据,会变动。 |
请求
curl -s "https://simsms.com/api/v1/pricing?service=telegram&country=england" \
-H "Authorization: Bearer $SIMSMS_KEY"
响应
{
"ok": true,
"service": "telegram",
"country": "england",
"price": 0.84,
"stock": 61213
}
可能返回 missing_key bad_key unknown_service no_stock rate_limited
所有国家的服务价格 #
GET
/api/v1/pricing?service={service}
不带国家参数,即可获取承载该服务的所有国家。排序是本站自定的:先看实际到码率,再在其中比价—而不是单纯按原始价格排序,那样会把一个两美分却没人能收到验证码的号码排在最前面。
参数
| 参数 | 说明 | |
|---|---|---|
service |
必填 | 服务代码,例如 telegram。 |
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
ok |
boolean | 在 200 响应中始终为 true。 |
service |
string | 您所请求的服务代码。 |
name |
string | 显示名称,例如「Telegram」。 |
countries |
array | 每个国家对应一个对象,顺序如上文所述。 |
countries[].country |
string | 国家代码,用于回传至配对调用。 |
countries[].name |
string | 英文名称。 |
countries[].price |
number | 一条验证码的美元价格。 |
countries[].stock |
integer | 当前可用线路数量。 |
请求
curl -s "https://simsms.com/api/v1/pricing?service=telegram" \
-H "Authorization: Bearer $SIMSMS_KEY"
响应
{
"ok": true,
"service": "telegram",
"name": "Telegram",
"countries": [
{ "country": "england", "name": "United Kingdom", "price": 0.84, "stock": 61213 },
{ "country": "poland", "name": "Poland", "price": 0.91, "stock": 22140 }
]
}
移动代理定价 #
GET
/api/v1/proxy-pricing?country={country}&tech={tech}
不指定国家时,返回我们部署调制解调器的四个国家,附运营商数量和起价;指定国家后,返回该国全部运营商及各租期价格。租期以天为单位:1、7、30、365。
参数
| 参数 | 说明 | |
|---|---|---|
country |
可选 | 国家代码,例如 us;留空则返回国家列表。 |
tech |
可选 | 网络代次,4g 或 5g。仅美国同时销售两种,其他国家将忽略此字段,只返回单一套餐。 |
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
ok |
boolean | 200 响应中恒为 true。 |
country |
string | 您所查询的国家。 |
tech |
string | 应用默认值后实际计价的网络代次。 |
techs |
array | 该国在售的全部网络代次。 |
terms |
array | 在售租期,单位为天。 |
carriers |
array | 每个运营商对应一个对象。 |
carriers[].carrier |
string | 运营商代码,用于下单。 |
carriers[].name |
string | 显示名称,例如「T-Mobile」。 |
carriers[].prices |
object | 各租期的美元价格,以天数为键。 |
请求
curl -s "https://simsms.com/api/v1/proxy-pricing?country=us" \
-H "Authorization: Bearer $SIMSMS_KEY"
响应
{
"ok": true,
"country": "us",
"tech": "4g",
"techs": ["4g", "5g"],
"terms": [1, 7, 30, 365],
"carriers": [
{ "carrier": "us-t-mobile", "name": "T-Mobile", "prices": { "1": 8.67, "7": 52, "30": 130, "365": 1300 } },
{ "carrier": "us-verizon", "name": "Verizon", "prices": { "1": 8.67, "7": 52, "30": 130, "365": 1300 } }
]
}
可能返回 missing_key bad_key unknown_country unknown_tech rate_limited
租用号码定价 #
GET
/api/v1/rental-pricing?country={country}&days={days}
不指定国家时,返回全部可租用号码的国家及起价;指定国家后,返回该国全部运营商及您所选租期的价格。
参数
| 参数 | 说明 | |
|---|---|---|
country |
可选 | 国家代码,例如 fr;留空则返回国家列表。 |
days |
可选 | 租期天数:7、14 或 30;其他数值将回退为最短租期。 |
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
ok |
boolean | 200 响应中恒为 true。 |
country |
string | 您所查询的国家。 |
days |
integer | 实际计价的租期。 |
terms |
array | 在售全部租期,单位为天。 |
operators |
array | 每个运营商对应一个对象,按价格从低到高排列。 |
operators[].operator |
string | 运营商代码,用于下单。 |
operators[].name |
string | 显示名称。 |
operators[].type |
string | physical、virtual 或 premium。 |
operators[].price |
number | 整个租期的美元总价。 |
请求
curl -s "https://simsms.com/api/v1/rental-pricing?country=fr&days=30" \
-H "Authorization: Bearer $SIMSMS_KEY"
响应
{
"ok": true,
"country": "fr",
"days": 30,
"terms": [7, 14, 30],
"operators": [
{ "operator": "fr-lycamobile", "name": "Lycamobile", "type": "virtual", "price": 14.32 },
{ "operator": "fr-orange", "name": "Orange", "type": "physical", "price": 20.76 }
]
}
完整示例 #
完整可运行的程序,而非单行代码片段——包括片段总会省略的两件事:处理错误格式,以及在 429 时退避重试。
Shell #
查找服务的最低价国家,并确认余额是否充足。
#!/usr/bin/env bash
set -euo pipefail
: "${SIMSMS_KEY:?export your key first}"
API="https://simsms.com/api/v1"
auth=(-H "Authorization: Bearer $SIMSMS_KEY")
# The catalogue is already ordered: the first country is the one to take.
best=$(curl -sf "${API}/pricing?service=telegram" "${auth[@]}" \
| jq -r ".countries[0] | \"\(.country) \(.price)\"")
country=${best% *}
price=${best#* }
balance=$(curl -sf "${API}/balance" "${auth[@]}" | jq -r .balance)
# ⚠️ Compare as numbers, not as strings: "9.5" > "10" is true in a string sort.
if awk "BEGIN{exit !($balance >= $price)}"; then
echo "ok: $country at \$$price, balance \$$balance"
else
echo "top up first: need \$$price, have \$$balance" >&2
exit 1
fi
JavaScript #
相同功能的 Node 版本,正确处理了错误结构。
const API = "https://simsms.com/api/v1";
const key = process.env.SIMSMS_KEY;
async function call(path) {
const r = await fetch(API + path, {
headers: { Authorization: `Bearer ${key}` },
});
const body = await r.json();
// A non-2xx always carries { ok:false, error }. Branch on `error`, never on
// the sentence — the string is stable, the wording is not.
if (!r.ok || !body.ok) {
if (body.error === "rate_limited") {
const wait = Number(r.headers.get("Retry-After") || 60);
await new Promise((s) => setTimeout(s, wait * 1000));
return call(path);
}
throw new Error(body.error ?? `http_${r.status}`);
}
return body;
}
const { countries } = await call("/pricing?service=telegram");
const { balance } = await call("/balance");
const best = countries[0];
console.log(`${best.name}: $${best.price} (${best.stock} in stock)`);
console.log(balance >= best.price ? "balance covers it" : "top up first");
Python #
以及 Python 版本,同样在 429 时重试。
import os, time, requests
API = "https://simsms.com/api/v1"
S = requests.Session()
S.headers["Authorization"] = f"Bearer {os.environ['SIMSMS_KEY']}"
def call(path):
r = S.get(API + path, timeout=20)
body = r.json()
if not r.ok or not body.get("ok"):
if body.get("error") == "rate_limited":
time.sleep(int(r.headers.get("Retry-After", 60)))
return call(path)
raise RuntimeError(body.get("error", f"http_{r.status_code}"))
return body
countries = call("/pricing?service=telegram")["countries"]
balance = call("/balance")["balance"]
best = countries[0]
print(f"{best['name']}: ${best['price']} ({best['stock']} in stock)")
print("balance covers it" if balance >= best["price"] else "top up first")
路线图 #
API 目前覆盖账户与目录查询。下单接口即将上线,将使用相同的基础地址和密钥——您现在构建的代码无需重写。
| 下单购买号码 | 计划中 计划中。目前下单仍通过网站完成。 |
|---|---|
| 轮询验证码 | 计划中 计划中,与下单接口同期上线。 |
| 释放号码 | 计划中 计划中,与下单接口同期上线。 |
| API 租用号码 | 计划中 计划中。 |
| Webhooks | 计划中 计划中,待有可推送的订单事件后上线。 |
本页面将随之扩充:以下各节保持不变,新增内容将加入「端点」部分下方。
更新日志 #
- 首个公开版本:密钥、GET /balance、GET /pricing。