ping…
# speedsms/api.py · v1 · REST + JSON

import speedsms

Покупай номера и получай SMS-коды из своего бота или скрипта.

сервисов = 0
стран = 0
лимит = "0/мин"
возврат = "0 мин"
# шаг 1 — выбрать странуapi.get("/countries")Цены уже с твоей скидкой, наличие и процент доходимости кода.
# шаг 2 — купить номерapi.post("/numbers")Списывается с баланса бота. max_price защитит от скачка цены.
# шаг 3 — забрать кодapi.get("/numbers/{id}")Раз в 3–5 секунд. Не пришёл за 20 минут — деньги вернутся сами.
class REST:
"""Обычные HTTP-запросы, ответы в JSON. Любой язык."""
class ОдинКлюч:
"""Создаётся в профиле бота. Перевыпуск — в один тап."""
class Возвраты:
"""Код не пришёл за 20 минут — деньги вернутся сами."""

def получить_ключ():

Открой @Speed_SMS_bot → Профиль → API для разработчиков → Создать ключ. То же самое есть в приложении. Там ключ можно посмотреть, скопировать, перевыпустить или отключить и увидеть число запросов.

# ВНИМАНИЕ: ключ даёт доступ к твоему балансу. Не публикуй его на GitHub и не передавай другим. Утёк — жми «Перевыпустить», старый перестанет работать сразу.

def авторизация():

Базовый адрес: https://speedsms.online/api/v1. Ключ передаётся в заголовке X-Api-Key (можно и Authorization: Bearer <ключ>). Формат ключа: ss_ + 40 символов.

curl https://speedsms.online/api/v1/me -H "X-Api-Key: ss_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def быстрый_старт(): # цена → покупка → код

import time, requests

API = "https://speedsms.online/api/v1"
H = {"X-Api-Key": "ss_..."}

r = requests.post(f"{API}/numbers", headers=H, json={"service": "tg", "country": 6, "max_price": 30}).json()
if not r["ok"]:
    raise SystemExit(r["message"])
num = r["number"]
print("Номер:", num["phone"])

while True:
    n = requests.get(f"{API}/numbers/{num['id']}", headers=H).json()["number"]
    if n["code"]:
        print("Код:", n["code"])
        requests.post(f"{API}/numbers/{num['id']}/finish", headers=H)
        break
    if n["status"] == "cancelled":
        print("Код не пришёл — деньги вернулись"); break
    time.sleep(5)
# 1. цены на номера Telegram по странам
curl "https://speedsms.online/api/v1/countries?service=tg" -H "X-Api-Key: $KEY"

# 2. купить номер (страна 6), не дороже 30 ₽
curl -X POST https://speedsms.online/api/v1/numbers -H "X-Api-Key: $KEY" \
  -H "Content-Type: application/json" -d '{"service":"tg","country":6,"max_price":30}'

# 3. проверить код (id из ответа шага 2)
curl https://speedsms.online/api/v1/numbers/123456789 -H "X-Api-Key: $KEY"
const API = "https://speedsms.online/api/v1";
const H = { "X-Api-Key": "ss_...", "Content-Type": "application/json" };

const buy = await fetch(`${API}/numbers`, { method: "POST", headers: H,
  body: JSON.stringify({ service: "tg", country: 6, max_price: 30 }) }).then(r => r.json());
if (!buy.ok) throw new Error(buy.message);
console.log("Номер:", buy.number.phone);

while (true) {
  const { number } = await fetch(`${API}/numbers/${buy.number.id}`, { headers: H }).then(r => r.json());
  if (number.code) { console.log("Код:", number.code); break; }
  if (number.status === "cancelled") { console.log("Код не пришёл — деньги вернулись"); break; }
  await new Promise(r => setTimeout(r, 5000));
}

def sdk(): # готовые библиотеки

Не хочешь писать запросы руками — возьми готовый клиент. Он сам повторяет запрос при лимите, ждёт код и выбирает страну с лучшей доходимостью.

# pip install https://speedsms.online/sdk/speedsms-1.0.0-py3-none-any.whl
# для aiogram/asyncio ещё: pip install aiohttp
from speedsms import SpeedSMS, SpeedSMSError

api = SpeedSMS("ss_...")
country = api.best_country("tg", max_price=30)
num = api.buy("tg", country["id"], max_price=30)
print("Номер:", num.phone)

code = api.wait_code(num.id)   # None - если код не пришёл и деньги вернулись
print("Код:", code)
// скачай https://speedsms.online/sdk/speedsms-js-1.0.0.zip (Node.js 18+, типы в комплекте)
import { SpeedSMS } from "./speedsms/index.mjs";

const api = new SpeedSMS("ss_...");
const country = await api.bestCountry("tg", 30);
const num = await api.buy("tg", country.id, 30);
console.log("Номер:", num.phone, "Код:", await api.waitCode(num.id));
# готовый Telegram-бот на aiogram 3 с номерами на нашем API:
# /buy tg, /buy wa 6 40, кнопка отмены, код приходит сам
curl -LO https://speedsms.online/sdk/speedsms-aiogram-bot.zip
pip install aiogram aiohttp https://speedsms.online/sdk/speedsms-1.0.0-py3-none-any.whl
BOT_TOKEN=... SPEEDSMS_KEY=ss_... python bot.py

class СкидкаЗаОбъём: # только через API

Чем больше покупаешь — тем дешевле номера через API. Считаются все твои покупки номеров за последние 30 дней (бот, приложение и API), без отменённых. Скидка применяется к покупкам через API автоматически, текущая ступень — в GET /me → volume.

покупки за 30 дней# скидка через API
до 10 000 ₽—
от 10 000 ₽−5%
от 50 000 ₽−10%

Личная скидка (промокод) со скидкой за объём не складывается — берётся большая из двух.

def песочница(ключ): # только чтение

Вставь свой ключ и отправь запрос прямо отсюда. Здесь только методы для чтения — ничего не купится и не спишется. Ключ никуда не сохраняется.

sandbox.py — запрос уходит из твоего браузера на speedsms.online/api/v1

class Ошибка(Exception):

Каждый ответ — JSON с полем ok. При успехе ok: true и данные метода. При ошибке ok: false, машинный код error, понятный текст message и HTTP-статус:

{"ok": false, "error": "funds", "message": "Недостаточно средств", "need": 12.5}
httperror# что значит
400badНеверные параметры запроса
401authНет ключа, неверный или отключённый ключ
402fundsНе хватает баланса; в need — сколько доплатить
403subscribe / captchaНужно подписаться на канал или пройти проверку в боте
404not_foundНомер не найден (или он не твой) / нет такого метода
405methodНе тот HTTP-метод (GET вместо POST и наоборот)
409no_numbersСейчас нет свободных номеров в этой стране
409price_too_highЦена выше твоего max_price; текущая — в price
409no_cancel / busyНомер уже закрыт / по аккаунту уже идёт покупка
425too_earlyОтменить можно через 2 минуты после покупки; в wait — сколько секунд ждать
429rateСлишком часто; в retry_after — через сколько секунд повторить
503maintenance / providerТехнический перерыв или временная проблема у поставщика номеров
500serverВнутренняя ошибка — повтори запрос

ЛИМИТ = 1000 # запросов в минуту на ключ

Проверять код достаточно раз в 3–5 секунд. Одна покупка за раз на аккаунт: параллельные покупки вернут busy.

class Статус(Enum):

status# что значит
waitingНомер выдан, ждём SMS
receivedКод пришёл — он в поле code
finishedНомер закрыт после получения кода
cancelledНомер отменён, деньги вернулись на баланс

def возвраты_и_отмена():

Если код не пришёл за 20 минут, номер закрывается сам и деньги возвращаются на баланс. Отменить номер вручную можно через 2 минуты после покупки (cancel_available_at), пока код не пришёл. После первого кода можно запросить ещё один (/resend), пока номер активен.

@get("/health") без ключа

Проверка, что API работает.

{"ok": true, "status": "ok", "now": "2026-10-12T12:00:00Z", "uptime_seconds": 86400}

@get("/me")

Твой аккаунт и баланс.

{"ok": true, "user_id": 123456789, "username": "nickname", "balance": 1284.5, "currency": "RUB",
 "volume": {"spent_30d": 12400, "discount_percent": 5, "next_tier": {"at": 50000, "percent": 10, "left": 37600},
            "tiers": [{"from": 10000, "percent": 5}, {"from": 50000, "percent": 10}]}}

@get("/services")

Все доступные сервисы. id передавай в service в других методах.

{"ok": true, "services": [{"id": "tg", "name": "Telegram"}, {"id": "wa", "name": "Whatsapp"}, …]}

@get("/countries")

параметртип# описание
servicestr, обязательныйid сервиса из /services

Страны с ценой (уже с твоей скидкой), наличием и тем, как часто приходит код по нашим покупкам за последние 2 суток.

{"ok": true, "service": "tg", "discount_percent": 0, "countries": [
  {"id": 6, "name": "Индонезия", "iso": "id", "price": 24, "count": 15230, "success_rate": 86, "avg_seconds": 40},
  …]}

@post("/numbers") списывает баланс

полетип# описание
servicestr, обязательныйid сервиса
countryint, обязательныйid страны из /countries
max_pricefloat, необязательныйНе покупать дороже этой суммы (₽) — защита от скачка цены

Покупает номер и сразу списывает цену с баланса.

{"ok": true, "balance": 1260.5, "number": {
  "id": 123456789, "phone": "+6281234567890", "service": "tg", "service_name": "Telegram",
  "country": 6, "country_name": "Индонезия", "price": 24, "status": "waiting", "code": null,
  "created_at": "2026-10-12T12:00:00Z", "expires_at": "2026-10-12T12:20:00Z",
  "cancel_available_at": "2026-10-12T12:02:00Z"}}

@get("/numbers")

параметр# описание
statusactive (по умолчанию: ждут кода и пришедшие за 30 минут) или all
limit1–100, по умолчанию 20
{"ok": true, "numbers": [{…}, {…}]}

@get("/numbers/{id}")

Статус номера и код. Пока кода нет — code: null, опрашивай раз в 3–5 секунд.

{"ok": true, "number": {"id": 123456789, "phone": "+6281234567890", "status": "received", "code": "58213", …}}

@post("/numbers/{id}/cancel")

Отменить номер и вернуть деньги. Доступно через 2 минуты после покупки и только пока код не пришёл.

{"ok": true, "refunded": 24, "balance": 1284.5}

@post("/numbers/{id}/finish")

Закрыть номер после получения кода (статус finished).

@post("/numbers/{id}/resend")

Запросить ещё один код на тот же номер (после первого кода, пока номер активен). Статус снова станет waiting.

if __name__ == "__main__": # полный цикл

import time, requests

API, H = "https://speedsms.online/api/v1", {"X-Api-Key": "ss_..."}

def call(method, path, **kw):
    r = requests.request(method, API + path, headers=H, timeout=30, **kw).json()
    if not r["ok"]:
        if r["error"] == "rate":
            time.sleep(r.get("retry_after", 5)); return call(method, path, **kw)
        raise RuntimeError(f'{r["error"]}: {r["message"]}')
    return r

# самая надёжная страна для Telegram - с лучшей доходимостью кода
countries = call("GET", "/countries", params={"service": "tg"})["countries"]
best = max(countries, key=lambda c: (c["success_rate"] or 0, -c["price"]))
num = call("POST", "/numbers", json={"service": "tg", "country": best["id"], "max_price": best["price"]})["number"]
print("Номер", num["phone"], "за", num["price"], "₽")

deadline = time.time() + 20 * 60
while time.time() < deadline:
    n = call("GET", f'/numbers/{num["id"]}')["number"]
    if n["code"]:
        print("Код:", n["code"]); call("POST", f'/numbers/{num["id"]}/finish'); break
    if n["status"] == "cancelled":
        print("Номер отменён, деньги вернулись"); break
    time.sleep(4)
if готов_подключить:
    # ключ создаётся за 5 секунд в профиле бота, вопросы — @help_speed
получить_ключ()