Разработчикам
Документация API
Читайте баланс и актуальную цену любого сервиса в любой стране прямо из своего кода. Один bearer-ключ, JSON поверх HTTPS, никакого SDK устанавливать не нужно.
Начало работы #
Всё работает по HTTPS в формате JSON и аутентифицируется одним ключом, который вы создаёте сами. Не нужно устанавливать SDK, подписывать договор или запрашивать песочницу — достаточно ключа и curl.
- 1 Создать ключ Откройте меню аккаунта, затем «Ключ API», затем «Создать ключ». Он показывается один раз: мы храним только его отпечаток, поэтому посмотреть его снова нельзя.
- 2 Отправляйте его как Bearer-токен Каждый запрос несёт заголовок Authorization. Другого способа входа нет — ни ключа в строке запроса, ни cookie, ни сессии.
- 3 Прочитать ответ Каждый ответ — это JSON-объект с полем ok. Если 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 | Всегда true при 200. |
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
}
Может вернуть missing_key bad_key rate_limited
Цена одного сервиса в одной стране #
GET
/api/v1/pricing?service={service}&country={country}
Актуальная цена и актуальное наличие для одной пары. Оба показателя меняются — цена следует за самой дешёвой сетью, предоставляющей этот сервис в этой стране, а наличие — то, что сеть сообщает прямо сейчас.
Параметры
| Параметр | Описание | |
|---|---|---|
service |
обязат. | Код сервиса, например telegram. Строчными буквами, из каталога. |
country |
необязат. | Код страны, например england. Оставьте пустым, чтобы получить сразу все страны — см. ниже. |
Поля ответа
| Поле | Тип | Описание |
|---|---|---|
ok |
boolean | Всегда true при 200. |
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 | Всегда true при 200. |
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 }
]
}
Может вернуть missing_key bad_key unknown_service rate_limited
Цена мобильного прокси #
GET
/api/v1/proxy-pricing?country={country}&tech={tech}
Без указания страны вы получаете четыре страны, где у нас есть модемы, с числом операторов и стартовой ценой. Указав страну — все операторы там и цену каждого срока. Сроки — в днях: 1, 7, 30, 365.
Параметры
| Параметр | Описание | |
|---|---|---|
country |
необязат. | Код страны, например us. Не указывайте его, чтобы получить список стран. |
tech |
необязат. | Поколение сети: 4g или 5g. Оба варианта продаются только в США; в остальных странах поле игнорируется и возвращается единый диапазон. |
Поля ответа
| Поле | Тип | Описание |
|---|---|---|
ok |
boolean | Всегда true при 200. |
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 | Всегда true при 200. |
country |
string | Страна, которую вы указали. |
days |
integer | Фактически применённый срок. |
terms |
array | Все доступные сроки, в днях. |
operators |
array | По одному объекту на оператора — сначала дешёвые. |
operators[].operator |
string | Код оператора — передайте его в заказ. |
operators[].name |
string | Его название. |
operators[].type |
string | physical, virtual or 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 }
]
}
Может вернуть missing_key bad_key unknown_country rate_limited
Полные примеры #
Полные рабочие программы, а не однострочные фрагменты — включая то, что фрагменты всегда упускают: обработку формата ошибки и повтор запроса при 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 | В планах В планах. |
| Вебхуки | В планах Планируется, когда появятся события заказов для отправки. |
Страница растёт вместе с ними: разделы ниже остаются на месте, а новые добавляются в «Конечные точки».
Изменения #
- Первая публичная версия: ключи, GET /balance, GET /pricing.