Preparación antes de ejecutar
Necesitas Python 3.10 o posterior y conexión a internet. El programa utiliza la biblioteca estándar, sin instalar un SDK ni paquetes con pip. Guarda el código como raysms_catalog.py. Mantén la verificación de certificados HTTPS; investiga los fallos de conexión en lugar de desactivarla.
Ejecuta python raysms_catalog.py para ver una parte de los catálogos actuales. El servicio se identifica mediante code y el país mediante id. Son identificadores del catálogo, no nombres ni prefijos telefónicos internacionales. No deduzcas el ID de un país a partir de un número.
Programa completo de solo lectura
El código es el mismo en los cuatro idiomas de la guía. Las etiquetas de consola y los nombres del catálogo aparecen en inglés. BASE_URL contiene el dominio canónico actual del sitio, sin credenciales. El tiempo límite y la salida explícita ante errores evitan repetir una consulta fallida indefinidamente.
# 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()
Elige un servicio real e interpreta el precio
Si tg figura en el catálogo actual, python raysms_catalog.py --service tg consulta sus países disponibles. Añade --country seguido de un ID del catálogo de países para limitar la búsqueda. Son ejemplos de sintaxis, no una promesa de disponibilidad de un servicio o país al ejecutar el programa.
price_micros usa microdólares enteros: 1.000.000 unidades equivalen a un USD. El ejemplo utiliza Decimal para evitar errores de redondeo binario. count indica la cantidad disponible al recibir la respuesta. Una lista items vacía significa que no hay ofertas para esa consulta; no se reserva ningún número.
Los precios y las existencias pueden cambiar. Una respuesta correcta del catálogo no garantiza una compra posterior, que la aplicación de destino acepte el número ni que se entregue el SMS.
Gestiona los errores antes de automatizar consultas
HTTP 429 exige reducir la frecuencia; respeta Retry-After cuando esté presente. El programa termina para que decidas cuándo reintentarlo. Un error de red, tiempo de espera o HTTP 5xx no debe provocar un bucle inmediato. En una integración mayor, comprueba la conexión y utiliza reintentos limitados con pausas crecientes.
No envíes cookies, contraseñas ni claves API en estas consultas públicas. Este ejemplo sirve para leer datos, no como proceso de compras de producción. No contiene llamadas de pago ni de creación de pedidos.
Añade compras solo tras una decisión explícita
La guía de desarrolladores explica autenticación, límite de precio, claves de idempotencia y estados del pedido. Léela antes de añadir POST /api/orders, ya que esa operación utiliza fondos del monedero. Un reintento debe corresponder a la misma compra prevista; investiga un resultado incierto en lugar de generar otro pedido silenciosamente.