Подготовка к запуску
Нужны Python 3.10 или новее и доступ к интернету. Используется стандартная библиотека: устанавливать SDK или пакеты через pip не требуется. Сохраните код в raysms_catalog.py. Оставьте проверку сертификатов HTTPS включённой; при ошибке соединения найдите причину вместо отключения проверки.
Запустите python raysms_catalog.py, чтобы увидеть часть текущих каталогов. Идентификатор сервиса хранится в поле code, страны — в id. Это идентификаторы каталога, а не названия стран и не телефонные коды. Нельзя определять ID страны по префиксу номера.
Полная программа только для чтения
Код одинаков во всех языковых версиях руководства. Подписи в консоли и названия из каталога будут английскими. BASE_URL содержит текущий канонический адрес сайта без секретов. Тайм-аут и явное завершение при ошибке предотвращают бесконечное повторение неудачного запроса.
# Python 3.10+; standard library only. No API key is needed.
import argparse
import json
from decimal import Decimal
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
BASE_URL = "https://raysms.com"
def get_items(path, **params):
query = urlencode({k: v for k, v in params.items() if v is not None})
url = BASE_URL + "/api/" + path + ("?" + query if query else "")
request = Request(url, headers={"Accept": "application/json",
"User-Agent": "RaySMS-Catalog-Example/1.0"},
method="GET")
try:
with urlopen(request, timeout=15) as response:
result = json.load(response)
except HTTPError as error:
if error.code == 429:
delay = error.headers.get("Retry-After", "the documented interval")
raise SystemExit("Rate limited; retry later after " + delay)
raise SystemExit("API returned HTTP " + str(error.code)
+ "; check the request and service availability")
except (URLError, TimeoutError):
raise SystemExit("Network request failed; check connectivity and retry later")
except (ValueError, UnicodeError):
raise SystemExit("API response was not valid JSON")
if not isinstance(result, dict) or not isinstance(result.get("items"), list):
raise SystemExit("Unexpected API response; inspect the API documentation")
return result["items"]
def main():
parser = argparse.ArgumentParser(description="Read the RaySMS catalog; never buy numbers")
parser.add_argument("--service", help="Service code from the catalog, for example tg")
parser.add_argument("--country", help="Optional country ID from the catalog")
args = parser.parse_args()
services = get_items("catalog/services", lang="en")
countries = get_items("catalog/countries", lang="en")
names = {str(country["id"]): country["name"] for country in countries}
if not args.service:
print("Services (first 20):")
for service in services[:20]:
print(service["code"], service["name"])
print("Countries (first 10):")
for country in countries[:10]:
print(country["id"], country["name"])
return
if args.service not in {service["code"] for service in services}:
parser.error("Unknown service code; run without arguments to inspect the catalog")
if args.country is not None and args.country not in names:
parser.error("Unknown country ID; inspect the country catalog")
offers = get_items("catalog/prices", service=args.service, country=args.country)
if not offers:
print("No available offers for this selection. No purchase was made.")
return
for offer in sorted(offers, key=lambda row: int(row["price_micros"]))[:10]:
price = Decimal(str(offer["price_micros"])) / Decimal("1000000")
country = str(offer["country"])
print(country, names.get(country, country),
"USD " + format(price, ".6f"), "available:", offer["count"])
if __name__ == "__main__":
main()
Выбор сервиса и чтение цены
Если tg присутствует в актуальном каталоге, команда python raysms_catalog.py --service tg покажет предложения по странам. Добавьте --country и ID из каталога стран для более узкого запроса. Это примеры синтаксиса, а не обещание наличия конкретного сервиса или страны в момент запуска.
Поле price_micros содержит целые микродоллары: 1 000 000 единиц равен одному USD. Для вывода используется Decimal, чтобы избежать ошибок двоичного округления. count — доступное количество на момент ответа. Пустой items означает отсутствие предложений по запросу; номер при этом не резервируется.
Наличие и цены могут измениться. Успешный ответ каталога не гарантирует последующую покупку, принятие номера целевым приложением или доставку SMS.
Обработка ошибок перед регулярными запросами
При HTTP 429 снизьте частоту запросов и учитывайте Retry-After, если заголовок указан. Пример завершается, позволяя повторить запрос осознанно. Сетевые ошибки, тайм-ауты и HTTP 5xx не должны запускать цикл без пауз. В рабочей системе проверяйте соединение и применяйте ограниченные повторные попытки с увеличением интервала.
Для публичного каталога не передавайте Cookie, пароль или ключ API. Программа предназначена для чтения данных, а не для производственной обработки покупок: в ней нет вызовов оплаты или создания заказов.
Переход к покупке требует отдельного решения
В руководстве разработчика описаны авторизация, предел цены, ключи идемпотентности и статусы заказа. Прочитайте его перед добавлением POST /api/orders: операция расходует средства кошелька. Повторный запрос должен относиться к той же покупке; неопределённый результат нужно проверить, а не незаметно заменить новым заказом.