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.pyclass СкидкаЗаОбъём: # только через API
Чем больше покупаешь — тем дешевле номера через API. Считаются все твои покупки номеров за последние 30 дней (бот, приложение и API), без отменённых. Скидка применяется к покупкам через API автоматически, текущая ступень — в GET /me → volume.
| покупки за 30 дней | # скидка через API |
|---|---|
| до 10 000 ₽ | — |
| от 10 000 ₽ | −5% |
| от 50 000 ₽ | −10% |
Личная скидка (промокод) со скидкой за объём не складывается — берётся большая из двух.
def песочница(ключ): # только чтение
Вставь свой ключ и отправь запрос прямо отсюда. Здесь только методы для чтения — ничего не купится и не спишется. Ключ никуда не сохраняется.
class Ошибка(Exception):
Каждый ответ — JSON с полем ok. При успехе ok: true и данные метода. При ошибке ok: false, машинный код error, понятный текст message и HTTP-статус:
{"ok": false, "error": "funds", "message": "Недостаточно средств", "need": 12.5}
| http | error | # что значит |
|---|---|---|
| 400 | bad | Неверные параметры запроса |
| 401 | auth | Нет ключа, неверный или отключённый ключ |
| 402 | funds | Не хватает баланса; в need — сколько доплатить |
| 403 | subscribe / captcha | Нужно подписаться на канал или пройти проверку в боте |
| 404 | not_found | Номер не найден (или он не твой) / нет такого метода |
| 405 | method | Не тот HTTP-метод (GET вместо POST и наоборот) |
| 409 | no_numbers | Сейчас нет свободных номеров в этой стране |
| 409 | price_too_high | Цена выше твоего max_price; текущая — в price |
| 409 | no_cancel / busy | Номер уже закрыт / по аккаунту уже идёт покупка |
| 425 | too_early | Отменить можно через 2 минуты после покупки; в wait — сколько секунд ждать |
| 429 | rate | Слишком часто; в retry_after — через сколько секунд повторить |
| 503 | maintenance / provider | Технический перерыв или временная проблема у поставщика номеров |
| 500 | server | Внутренняя ошибка — повтори запрос |
ЛИМИТ = 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")
| параметр | тип | # описание |
|---|---|---|
service | str, обязательный | 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") списывает баланс
| поле | тип | # описание |
|---|---|---|
service | str, обязательный | id сервиса |
country | int, обязательный | id страны из /countries |
max_price | float, необязательный | Не покупать дороже этой суммы (₽) — защита от скачка цены |
Покупает номер и сразу списывает цену с баланса.
{"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")
| параметр | # описание |
|---|---|
status | active (по умолчанию: ждут кода и пришедшие за 30 минут) или all |
limit | 1–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)