
Коротко
С 28 октября 2026 года запросы к hero-sms.com не проходят: регистратор заморозил домен, и его адрес не находится в DNS. Ваш код не сломан, но автоматические покупки стоят. Чтобы они снова пошли, переведите интеграцию на REST API Hush SMS: getNumber → POST /v1/numbers, getStatus → GET /v1/numbers/{id}, setStatus 8 и 6 → отмена и завершение заказа. Ниже таблица замены и адаптер, который возвращает привычные ответы вроде ACCESS_NUMBER, чтобы остальной код не трогать.
Эта инструкция для тех, у кого покупка номеров встроена в бота, скрипт или сервис через HeroSMS API. Если вам просто нужен один код, купите номер в боте @HushNumBot или на сайте, а что случилось с доменом, читайте в статье «HeroSMS не работает».
Как понять, что дело в hero-sms.com
Если интеграция перестала покупать номера вечером 28 октября, а в логах одна из этих ошибок, проблема не в вашем сервере и не в ключе:
| Где | Ошибка в логе |
|---|---|
| curl | curl: (6) Could not resolve host: hero-sms.com |
| Python, requests (Linux) | Failed to resolve 'hero-sms.com' ([Errno -2] Name or service not known) |
| Node.js | getaddrinfo ENOTFOUND hero-sms.com |
| PHP, Guzzle | cURL error 6: Could not resolve host: hero-sms.com |
| Go | dial tcp: lookup hero-sms.com: no such host |
Если у вас запросы пока проходят, сервер помнит старый IP из кэша DNS. Когда запись устареет, всё упадёт так же, поэтому подключайте запасной канал сейчас, а не в момент сбоя.
Что меняется при переезде
- REST и JSON вместо одного адреса
handler_api.phpс параметромactionи текстовых ответов; - ключ передаётся в заголовке
Authorization: Bearer, а не в параметреapi_key; - у покупки обязательный заголовок
Idempotency-Key: повтор с тем же ключом вернёт тот же заказ, а не купит второй номер; - цены и баланс в ответах API в рублях;
- коды можно получать через webhooks, а не только опросом статуса.
Базовый адрес API: https://api.hush-sms.com. Полный справочник с примерами: docs.hush-sms.com.
Чем заменить методы HeroSMS
| HeroSMS, handler_api.php | Hush SMS API |
|---|---|
getBalance | GET /v1/me: профиль и баланс |
getNumber, getNumberV2 | POST /v1/numbers с телом {"service", "country"} и заголовком Idempotency-Key |
getStatus, getStatusV2 | GET /v1/numbers/{id}: статус и коды в поле sms_codes; все SMS заказа: GET /v1/orders/{id}/sms |
setStatus, status=8 | POST /v1/numbers/{id}/cancel: отменить заказ |
setStatus, status=6 | POST /v1/orders/{id}/finish: завершить заказ |
setStatus, status=3 | Отдельного метода нет: повторный код можно запросить в боте или в личном кабинете |
getActiveActivations | GET /v1/numbers: активные заказы |
getPrices, getServicesList, getCountries | GET /v1/services, GET /v1/services/{code}/countries, GET /v1/services/{code}/offers |
Коды сервисов и ID стран не переносите вслепую из старой интеграции: возьмите их из GET /v1/services и GET /v1/services/{code}/countries. ID страны в запросе покупки числовой, как и раньше.
Ответы и статусы
| Ответ HeroSMS | Что вернёт Hush SMS |
|---|---|
ACCESS_NUMBER:id:номер | 201 и объект order с полями id, phone_number, status, price |
NO_NUMBERS | 404 с кодом not_available |
NO_BALANCE | 402 с кодом insufficient_funds |
BAD_KEY | 401: ключа нет или он неверный |
STATUS_WAIT_CODE | status: pending: номер выдан, ждём SMS |
STATUS_OK:код | status: sms_received, код в sms_codes |
STATUS_CANCEL | status: canceled, затем refunded: деньги вернулись на баланс |
EARLY_CANCEL_DENIED | 409 с кодом too_early; в details.seconds_left сколько секунд осталось |
Адаптер: старые ответы, новый API
Если вызовы HeroSMS разбросаны по коду, проще всего заменить один модуль. Этот адаптер на Python отвечает теми же строками, что и handler_api.php, поэтому остальной код можно не менять. Нужна только библиотека requests.
import uuid
import requests
API = "https://api.hush-sms.com/v1"
class HushAdapter:
"""Ответы как у handler_api.php, внутри REST API Hush SMS."""
def __init__(self, api_key):
self.http = requests.Session()
self.http.headers["Authorization"] = f"Bearer {api_key}"
def _call(self, method, path, **kwargs):
response = self.http.request(method, API + path, timeout=30, **kwargs)
data = response.json() if response.content else {}
failed = response.status_code >= 400
error = data.get("error", {}).get("code") if failed else None
return error, data
def get_number(self, service, country, idempotency_key=None):
# Храните ключ, пока не получили ответ: повтор с ним не купит второй номер.
key = idempotency_key or str(uuid.uuid4())
body = {"service": service, "country": int(country)}
headers = {"Idempotency-Key": key}
error, data = self._call("POST", "/numbers", json=body, headers=headers)
if error == "not_available":
return "NO_NUMBERS"
if error == "insufficient_funds":
return "NO_BALANCE"
if error:
return f"ERROR:{error}"
order = data["order"]
return f"ACCESS_NUMBER:{order['id']}:{order['phone_number'].lstrip('+')}"
def get_status(self, order_id):
error, data = self._call("GET", f"/numbers/{order_id}")
if error:
return f"ERROR:{error}"
order = data["order"]
if order.get("sms_codes"):
return f"STATUS_OK:{order['sms_codes'][-1]}"
if order["status"] in ("canceled", "refunded"):
return "STATUS_CANCEL"
return "STATUS_WAIT_CODE"
def set_status(self, order_id, status):
if int(status) == 8:
error, _ = self._call("POST", f"/numbers/{order_id}/cancel")
if error == "too_early":
return "EARLY_CANCEL_DENIED"
return f"ERROR:{error}" if error else "ACCESS_CANCEL"
if int(status) == 6:
error, _ = self._call("POST", f"/orders/{order_id}/finish")
return f"ERROR:{error}" if error else "ACCESS_ACTIVATION"
return "BAD_STATUS"
Два места, где адаптер стоит доработать под себя. Первое: при ответах 503 и 504 на покупку повторяйте запрос с тем же Idempotency-Key, а не с новым, иначе можно купить два номера. Второе: опрос статуса не чаще раза в несколько секунд, а лучше webhooks.
Правила, которые отличаются
- отменить заказ можно, пока на него не пришла SMS, и не раньше чем через 2 минуты после покупки;
- если SMS не пришла за 15 минут, заказ закрывается сам, а деньги возвращаются на баланс;
- если цена поставщика изменилась во время покупки, в ответе будут
price_changed: trueи прежняя цена; - на ответы
503и504сначала проверьте статус заказа и только потом повторяйте действие.
Webhooks вместо опроса
Адрес для webhooks задаётся в разделе API Telegram-бота. Когда приходит SMS, Hush SMS отправляет на него POST-запрос с кодом, а опрос статуса можно оставить как запасной. Формат запроса описан в разделе Webhooks документации.
План переезда за вечер
- Получите ключ API в боте @HushNumBot или в настройках личного кабинета и пополните баланс.
- Подставьте адаптер вместо модуля, который обращался к
handler_api.php. - Проверьте полный цикл на одном сервисе: покупка, код, завершение и отмена.
- Подключите webhooks и оставьте опрос статуса как запасной вариант.
- Переведите поток заказов и держите второго поставщика в коде на случай следующего сбоя.
Частые вопросы
Есть ли у Hush SMS адрес, совместимый с handler_api.php?
Нет, у Hush SMS свой REST API. Быстрее всего переехать через адаптер выше: он отвечает теми же строками, что и старый API.
Где взять ключ API?
В Telegram-боте @HushNumBot, в разделе API, или в настройках личного кабинета на сайте. Ключ передаётся в заголовке Authorization: Bearer.
Перенесётся ли мой баланс с HeroSMS?
Нет, это разные сервисы. В Hush SMS баланс пополняется отдельно: в боте через СБП, криптовалюту и Telegram Stars, на сайте криптовалютой.
Что делать, если hero-sms.com снова заработает?
Оставьте Hush SMS вторым поставщиком в коде и переключайтесь на него при ошибках первого. Так следующий сбой одного сервиса не остановит ваши покупки.
Переносите интеграцию? Получите ключ API и начните с одного тестового заказа.