getBalance
El saldo de la cuenta en dólares.
Solo api_key y action.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getBalanceRespuesta
ACCESS_BALANCE:25.00Si tu software ya funciona con un servicio de activaciones mediante handler_api.php, funciona con RelySMS: cambia la dirección del servidor y la clave. Mismas acciones, mismas respuestas, nuestros precios y reembolsos.
https://relysms.pro/stubs/handler_api.phpCada petición es un GET o POST a una sola dirección, con parámetros en la URL o en un formulario. La clave va en api_key y la acción en action.
getBalanceEl saldo de la cuenta en dólares.
Solo api_key y action.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getBalanceRespuesta
ACCESS_BALANCE:25.00getNumberComprar un número para un servicio en un país. Se cobra al momento; se reembolsa si no llega el código. Respuesta: ACCESS_NUMBER:número_de_pedido:teléfono.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
service | sí | Código del servicio (getServicesList), p. ej. tg. |
country | sí | Código del país (getCountries). |
maxPrice | no | Precio máximo en dólares. Si es más caro: WRONG_MAX_PRICE con el precio actual, sin cobro. |
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getNumber&service=tg&country=187&maxPrice=0.80Respuesta
ACCESS_NUMBER:1042:15550001111Errores posibles: BAD_SERVICE, BAD_COUNTRY, NO_NUMBERS, NO_BALANCE, WRONG_MAX_PRICE:0.59, LIMIT_ACTIVATIONS, RATE_LIMIT, BANNED
getNumberV2Igual que getNumber, con respuesta JSON que incluye el precio y los tiempos de la ventana.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
service | sí | Código del servicio. |
country | sí | Código del país. |
maxPrice | no | Precio máximo en dólares. |
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getNumberV2&service=tg&country=187&maxPrice=0.80Respuesta
{
"activationId": 1042,
"phoneNumber": "15550001111",
"activationCost": 0.59,
"countryCode": "187",
"canGetAnotherSms": true,
"activationTime": "2026-10-27T10:00:00.000Z",
"activationEndTime": "2026-10-27T10:20:00.000Z"
}Errores posibles: BAD_SERVICE, BAD_COUNTRY, NO_NUMBERS, NO_BALANCE, WRONG_MAX_PRICE:0.59, LIMIT_ACTIVATIONS, RATE_LIMIT
getStatusEstado del pedido: esperando código, código recibido (con el código) o cancelado.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
id | sí | Número de pedido de getNumber. |
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getStatus&id=1042Respuesta
STATUS_OK:48213Errores posibles: NO_ACTIVATION
setStatusActuar sobre un pedido: listo, otro código, terminar, cancelar (ver Estados).
| Parámetro | Obligatorio | Descripción |
|---|---|---|
id | sí | Número de pedido. |
status | sí | 1, 3, 6 u 8. |
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=setStatus&id=1042&status=6Respuesta
ACCESS_ACTIVATIONErrores posibles: NO_ACTIVATION, BAD_STATUS, EARLY_CANCEL_DENIED, ERROR_SQL
getActiveActivationsTodos los pedidos abiertos de la clave: número, estado, códigos y textos recibidos.
Solo api_key y action.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getActiveActivationsRespuesta
{
"status": "success",
"activeActivations": [
{
"activationId": 1042,
"serviceCode": "tg",
"phoneNumber": "15550001111",
"activationCost": 0.59,
"activationStatus": "2",
"smsCode": ["48213"],
"smsText": ["Telegram code: 48213"],
"activationTime": "2026-10-27T10:00:00.000Z",
"countryCode": "187"
}
]
}getPricesNuestros precios en dólares y cuántos números hay aproximadamente. Sin parámetros: todo lo que está a la venta.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
service | no | Solo este servicio. |
country | no | Solo este país. |
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getPrices&service=tg&country=187Respuesta
{ "187": { "tg": { "cost": 0.59, "count": 1000 } } }Errores posibles: BAD_SERVICE, BAD_COUNTRY
getCountriesPaíses con códigos del protocolo y nombres en ruso e inglés.
Solo api_key y action.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getCountriesRespuesta
{ "187": { "id": 187, "rus": "США", "eng": "United States", "visible": 1 } }getServicesListServicios con códigos del protocolo.
Solo api_key y action.
GET https://relysms.pro/stubs/handler_api.php?api_key=KEY&action=getServicesListRespuesta
{ "status": "success", "services": [{ "code": "tg", "name": "Telegram" }] }Valores de status en setStatus:
status=1 → ACCESS_READY — El número está introducido en el servicio; esperando código. No cambia nada; se mantiene por compatibilidad.status=3 → ACCESS_RETRY_GET — Pedir otro código al mismo número: después del primer código y mientras el pedido siga abierto. Gratis. Hasta que llegue, getStatus responde STATUS_WAIT_RETRY.status=6 → ACCESS_ACTIVATION — Terminar el pedido tras el código. No llegarán más SMS al número.status=8 → ACCESS_CANCEL — Cancelar un pedido sin código (no antes de 2 minutos). El dinero vuelve a tu saldo.Respuestas de getStatus:
STATUS_WAIT_CODE — Aún no hay código: vuelve a preguntar en 5–10 segundos.STATUS_OK:48213 — Llegó el código; tras los dos puntos va el código (o el texto del SMS si no lo contiene).STATUS_WAIT_RETRY:48213 — Se pidió otro código y aún no llegó; tras los dos puntos va el código anterior.STATUS_CANCEL — Cancelado o cerrado sin código; el dinero ya está en tu saldo.Los errores llegan como texto plano, como es habitual en este protocolo. Todos, salvo RATE_LIMIT, llegan con estado 200.
NO_KEY | Falta api_key. |
BAD_KEY | Clave incorrecta o desactivada, o cuenta bloqueada. |
BAD_ACTION | Acción desconocida. |
BAD_SERVICE | No existe ese código de servicio. |
BAD_COUNTRY | No existe ese código de país. |
NO_NUMBERS | Ahora no hay números para esa combinación; no se cobró nada. |
NO_BALANCE | Menos de $20 de saldo (umbral de la API) o menos que el precio. |
WRONG_MAX_PRICE | El precio supera maxPrice; tras los dos puntos va el precio actual. |
LIMIT_ACTIVATIONS | Demasiados pedidos abiertos: termina o cancela algunos. |
RATE_LIMIT | Demasiado frecuente; HTTP 429. Reintenta en un segundo. |
BANNED | La cuenta está bloqueada: contacta con soporte. |
NO_ACTIVATION | No hay ningún pedido con ese número para esta clave. |
BAD_STATUS | Esa acción no está disponible ahora para el pedido (p. ej., terminar sin código). |
EARLY_CANCEL_DENIED | Solo se puede cancelar 2 minutos después de la compra. |
ERROR_SQL | Error temporal de nuestro lado: repite la solicitud en un minuto. |
Los códigos son los estándar del protocolo: tg — Telegram, wa — WhatsApp, etc.; el país 187 — EE. UU. getServicesList y getCountries devuelven las listas completas: toma los códigos de ahí, no de tablas antiguas, porque servicios y países cambian con el stock.
Los mismos números y las mismas reglas que handler_api.php, en JSON: servicios por nombre (telegram), países por código ISO (US), estados HTTP y códigos de error con los que un programa puede decidir. Úsala para código nuevo; deja handler_api.php para el software que ya lo usa.
https://relysms.pro/api/v1Envía la clave en un encabezado: Authorization: Bearer <clave> (o X-Api-Key: <clave>). Nunca en la URL: las URL acaban en los logs. Los límites, el mínimo de $20 y el catálogo son los mismos que en handler_api.php.
Añade el encabezado Idempotency-Key con un valor propio (un UUID, hasta 255 caracteres) en POST /orders y /orders/batch. Si se corta la conexión y repites la petición con la misma clave, recibes la primera respuesta (con el encabezado Idempotent-Replayed: true) y no se compra nada dos veces. La misma clave con otro cuerpo se rechaza; una repetición que llega mientras la primera sigue en curso recibe idempotency_in_progress. Las respuestas correctas se guardan 24 horas; una compra fallida no cobró nada y puede repetirse con la misma clave.
POST /orders/batch compra hasta 20 números de un servicio y país en una sola petición: es la forma de comprar más de 5 por segundo. Las compras van una tras otra; la primera que falla detiene el lote, y la respuesta trae lo comprado y el motivo en stoppedBy. Si no se compró nada, la respuesta es ese error.
GET /orders devuelve primero los más nuevos. Si next no es null, pásalo como before para obtener la página siguiente.
En lugar de consultar GET /orders/{id}, define una dirección HTTPS con PUT /webhook y te enviaremos un POST cuando algo le pase a un pedido comprado por la API. El cuerpo trae el pedido tal como está al enviarse. Responde con cualquier 2xx en 10 segundos; un pedido puede generar varios eventos y el mismo evento puede llegar dos veces tras un reintento, así que usa el id de la entrega.
order.code_received — Llegó un código (cada nuevo lo envía otra vez).order.finished — El pedido se terminó: por ti, o al acabarse su tiempo después de un código.order.cancelled — Cancelado sin código; el dinero volvió al saldo.order.expired — Se acabó el tiempo sin código; el dinero volvió al saldo.ping — Una prueba de POST /webhook/test; order es null.POST /relysms-hook HTTP/1.1
Content-Type: application/json
X-RelySMS-Event: order.code_received
X-RelySMS-Delivery: cm…
X-RelySMS-Signature: t=1793095272,v1=5f2b…
{
"id": "cm…",
"event": "order.code_received",
"createdAt": "2026-10-27T10:01:12.000Z",
"order": { "id": 1042, "status": "received", "codes": [{ "code": "48213", … }], … }
}Cada petición trae X-RelySMS-Signature: t=<hora unix>,v1=<firma>. La firma es HMAC-SHA256 de la cadena "t.cuerpo" (el cuerpo tal cual, byte a byte) con el secreto del webhook, en hex. Verifícala, y que t no tenga más de 5 minutos, antes de confiar en el cuerpo.
Python
import hashlib, hmac, time
def verify(secret: str, body: bytes, header: str, tolerance=300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t, sig = parts.get("t", ""), parts.get("v1", "")
if not t.isdigit() or abs(time.time() - int(t)) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig)Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(secret, rawBody, header, tolerance = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const t = Number(parts.t);
if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > tolerance) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return expected.length === parts.v1?.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}Si tu servidor no responde 2xx, reintentamos a los 10 segundos, 1 minuto, 5 minutos, 30 minutos, 2 horas y 6 horas —7 intentos en total— y luego lo dejamos. GET /webhook/deliveries muestra qué se envió y qué falló.
GET /balanceEl saldo en dólares y si alcanza para comprar por la API.
curl -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/balanceRespuesta
{ "balance": 25, "currency": "USD", "canBuy": true, "apiMinimum": 20 }GET /servicesTodos los servicios a la venta: nuestro id, el nombre y el código de handler_api.php.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
lang query | no | Idioma de los nombres: en (por defecto), ru, uk, zh, es, pt, id, vi, tr, ar, fr. |
curl -H "Authorization: Bearer $KEY" "https://relysms.pro/api/v1/services?lang=en"Respuesta
{ "services": [{ "id": "telegram", "name": "Telegram", "protocolCode": "tg" }] }GET /countriesTodos los países a la venta: código ISO, nombre y código de handler_api.php.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
lang query | no | Idioma de los nombres: en (por defecto), ru, uk, zh, es, pt, id, vi, tr, ar, fr. |
curl -H "Authorization: Bearer $KEY" "https://relysms.pro/api/v1/countries?lang=en"Respuesta
{ "countries": [{ "id": "US", "name": "United States", "protocolCode": 187 }] }GET /pricesNuestros precios en dólares y cuántos números hay aproximadamente. Sin parámetros, todo lo que está a la venta.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
service query | no | Id del servicio de /services, p. ej. telegram. |
country query | no | Código ISO del país de /countries, p. ej. US. |
curl -H "Authorization: Bearer $KEY" "https://relysms.pro/api/v1/prices?service=telegram"Respuesta
{ "prices": [{ "service": "telegram", "country": "US", "price": 0.59, "stock": 1000 }] }Errores posibles: unknown_service, unknown_country
POST /ordersComprar un número. Se cobra al instante y se devuelve si no llega el código.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
service body | sí | Id del servicio de /services, p. ej. telegram. |
country body | sí | Código ISO del país de /countries, p. ej. US. |
maxPrice body | no | Precio máximo en dólares, un número. Por encima: price_above_max con el precio actual, sin cobro. |
curl -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: 7c1f0e2a-run-1" \
-d '{"service":"telegram","country":"US","maxPrice":0.8}' \
https://relysms.pro/api/v1/ordersRespuesta
{
"order": {
"id": 1042,
"service": "telegram",
"country": "US",
"phone": "15550001111",
"price": 0.59,
"status": "waiting",
"refunded": false,
"codes": [],
"awaitingAnotherCode": false,
"createdAt": "2026-10-27T10:00:00.000Z",
"expiresAt": "2026-10-27T10:20:00.000Z",
"cancelableAt": "2026-10-27T10:02:00.000Z"
}
}Errores posibles: bad_request, unknown_service, unknown_country, no_numbers, insufficient_balance, below_api_minimum, price_above_max, too_many_open_orders, buying_too_fast, idempotency_key_reused, idempotency_in_progress
POST /orders/batchComprar hasta 20 números de un servicio y país en una sola petición.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
service body | sí | Id del servicio de /services, p. ej. telegram. |
country body | sí | Código ISO del país de /countries, p. ej. US. |
quantity body | sí | Cuántos números, de 1 a 20. |
maxPrice body | no | Precio máximo en dólares, un número. Por encima: price_above_max con el precio actual, sin cobro. |
curl -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: 7c1f0e2a-batch-1" \
-d '{"service":"telegram","country":"US","quantity":5}' \
https://relysms.pro/api/v1/orders/batchRespuesta
{
"orders": [{ "id": 1043, "phone": "15550001112", … }, { "id": 1044, … }],
"requested": 5,
"placed": 2,
"stoppedBy": { "code": "no_numbers", "message": "…" }
}Errores posibles: bad_request, unknown_service, unknown_country, no_numbers, insufficient_balance, below_api_minimum, price_above_max, too_many_open_orders, buying_too_fast, idempotency_key_reused, idempotency_in_progress
GET /ordersTus pedidos, los más nuevos primero: los abiertos por defecto, o todos.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
status query | no | open (por defecto): esperando o con código; all: todos los pedidos. |
limit query | no | Pedidos por página, de 1 a 100 (por defecto 50). |
before query | no | El valor next de la página anterior. |
curl -H "Authorization: Bearer $KEY" "https://relysms.pro/api/v1/orders?status=all&limit=50"Respuesta
{ "orders": [{ "id": 1042, … }], "next": "1001" }Errores posibles: bad_request
GET /orders/{id}Un pedido con sus códigos. Consulta cada 5–10 segundos mientras el estado sea waiting.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
id path | sí | El id del pedido de la respuesta de compra. |
curl -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/orders/1042Respuesta
{
"order": {
"id": 1042,
"status": "received",
"codes": [{ "code": "48213", "text": "Telegram code: 48213", "receivedAt": "2026-10-27T10:01:12.000Z" }],
…
}
}Errores posibles: not_found
POST /orders/{id}/finishTerminar un pedido con código. El número no recibirá más SMS. Repetirlo no hace daño.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
id path | sí | El id del pedido de la respuesta de compra. |
curl -X POST -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/orders/1042/finishRespuesta
{ "order": { "id": 1042, "status": "finished", … } }Errores posibles: not_found, invalid_state
POST /orders/{id}/another-codeOtro código al mismo número: después del primer código y mientras el pedido siga abierto. Gratis. Hasta que llegue, el pedido tiene awaitingAnotherCode = true.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
id path | sí | El id del pedido de la respuesta de compra. |
curl -X POST -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/orders/1042/another-codeRespuesta
{ "order": { "id": 1042, "status": "received", "awaitingAnotherCode": true, … } }Errores posibles: not_found, invalid_state, try_later
POST /orders/{id}/cancelCancelar un pedido sin código, a partir de 2 minutos tras la compra. El dinero vuelve al instante.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
id path | sí | El id del pedido de la respuesta de compra. |
curl -X POST -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/orders/1042/cancelRespuesta
{ "order": { "id": 1042, "status": "cancelled", "refunded": true, … } }Errores posibles: not_found, invalid_state, too_early_to_cancel
GET /webhookLa dirección del webhook y su secreto de firma, o null.
curl -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/webhookRespuesta
{ "webhook": { "url": "https://example.com/relysms-hook", "secret": "whsec_…", "createdAt": "2026-10-27T10:00:00.000Z" } }PUT /webhookDefinir o cambiar la dirección. El secreto se crea una vez y se conserva; rotateSecret crea uno nuevo.
| Parámetro | Obligatorio | Descripción |
|---|---|---|
url body | sí | Dirección HTTPS de tu servidor. Se rechazan direcciones privadas y locales. |
rotateSecret body | no | true: crear un nuevo secreto de firma. |
curl -X PUT -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"url":"https://example.com/relysms-hook"}' \
https://relysms.pro/api/v1/webhookRespuesta
{ "webhook": { "url": "https://example.com/relysms-hook", "secret": "whsec_…", "createdAt": "2026-10-27T10:00:00.000Z" } }Errores posibles: bad_request, invalid_webhook_url
DELETE /webhookQuitar el webhook. Los eventos aún no enviados se descartan.
curl -X DELETE -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/webhookRespuesta
{ "webhook": null }POST /webhook/testEnviar un evento ping para comprobar la dirección y la firma.
curl -X POST -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/webhook/testRespuesta
{ "delivery": { "id": "cm…" } }Errores posibles: not_found
GET /webhook/deliveriesLas últimas 20 entregas: evento, estado, intentos, última respuesta de tu servidor.
curl -H "Authorization: Bearer $KEY" https://relysms.pro/api/v1/webhook/deliveriesRespuesta
{
"deliveries": [{
"id": "cm…", "event": "order.code_received", "orderId": 1042,
"status": "pending", "attempts": 2, "lastHttpStatus": 502, "lastError": "HTTP 502",
"createdAt": "2026-10-27T10:01:12.000Z", "deliveredAt": null, "nextAttemptAt": "2026-10-27T10:02:22.000Z"
}]
}El campo status de un pedido:
waiting — El número es tuyo y aún no llegó ningún código.received — Llegó un código; está en codes. Pueden llegar más mientras el pedido siga abierto.finished — Terminaste el pedido (o se acabó su tiempo después de un código).cancelled — Cancelado sin código; refunded es true y el dinero está en el saldo.expired — Se acabó el tiempo sin código; el dinero volvió al saldo.Un error es un estado HTTP y un JSON con code para que el programa decida y message para las personas. Algunos traen campos extra (price, cancelableAt, apiMinimum).
{ "error": { "code": "price_above_max", "message": "The price is above maxPrice.", "price": 0.59 } }missing_key | 401 | No hay clave en Authorization ni en X-Api-Key. |
invalid_key | 401 | La clave es incorrecta, fue reemplazada o la cuenta está bloqueada. |
bad_request | 400 | El cuerpo o un parámetro es incorrecto; message dice cuál. |
unknown_service | 400 | No existe ese id de servicio. |
unknown_country | 400 | No existe ese código de país. |
idempotency_key_invalid | 400 | Idempotency-Key está vacío o supera los 255 caracteres. |
invalid_webhook_url | 400 | La dirección del webhook no es HTTPS, no es una URL o apunta a un servidor privado o local. |
insufficient_balance | 402 | El saldo es menor que el precio. |
below_api_minimum | 402 | Menos de $20 de saldo: la API solo compra desde $20. |
account_blocked | 403 | La cuenta está bloqueada: escribe a soporte. |
not_found | 404 | No hay pedido con ese id para esta clave. |
no_numbers | 409 | No hay números para este par ahora; no se cobró nada. |
price_above_max | 409 | El precio supera maxPrice; price trae el actual. |
too_many_open_orders | 409 | Demasiados pedidos abiertos: termina o cancela algunos. |
invalid_state | 409 | No es posible en este estado (p. ej. terminar sin código). |
too_early_to_cancel | 409 | Se puede cancelar desde cancelableAt, 2 minutos tras la compra. |
idempotency_in_progress | 409 | Una petición con este Idempotency-Key sigue en curso; repite en un momento. |
idempotency_key_reused | 422 | Este Idempotency-Key ya se usó para otra petición. |
rate_limited | 429 | Más de 20 peticiones por segundo; Retry-After indica cuándo repetir. |
buying_too_fast | 429 | Más de 5 compras por segundo; usa /orders/batch. |
try_later | 503 | No funcionó por ahora; inténtalo en un minuto. |
Comprar un número, esperar el código, terminar el pedido.
Python
import time, uuid, requests
BASE = "https://relysms.pro/api/v1"
S = requests.Session()
S.headers["Authorization"] = "Bearer rs_your_key"
r = S.post(f"{BASE}/orders",
json={"service": "telegram", "country": "US", "maxPrice": 0.8},
headers={"Idempotency-Key": str(uuid.uuid4())}, timeout=30)
if r.status_code != 201:
raise SystemExit(r.json()["error"]) # no_numbers, below_api_minimum, …
order = r.json()["order"]
print("number:", order["phone"])
while order["status"] == "waiting": # up to 20 minutes
time.sleep(10)
order = S.get(f"{BASE}/orders/{order['id']}", timeout=30).json()["order"]
if order["status"] == "received":
print("code:", order["codes"][-1]["code"])
S.post(f"{BASE}/orders/{order['id']}/finish", timeout=30)
# "expired" or "cancelled": the money is back on the balanceNode.js
const BASE = "https://relysms.pro/api/v1";
const headers = { Authorization: "Bearer rs_your_key", "Content-Type": "application/json" };
const res = await fetch(`${BASE}/orders`, {
method: "POST",
headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({ service: "telegram", country: "US", maxPrice: 0.8 }),
});
if (res.status !== 201) throw new Error((await res.json()).error.code);
let { order } = await res.json();
console.log("number:", order.phone);
while (order.status === "waiting") {
await new Promise((r) => setTimeout(r, 10_000));
({ order } = await (await fetch(`${BASE}/orders/${order.id}`, { headers })).json());
}
if (order.status === "received") {
console.log("code:", order.codes.at(-1).code);
await fetch(`${BASE}/orders/${order.id}/finish`, { method: "POST", headers });
}El ciclo completo: comprar un número, esperar el código y terminar el pedido.
curl
KEY=rs_your_key
BASE=https://relysms.pro/stubs/handler_api.php
curl "$BASE?api_key=$KEY&action=getBalance"
curl "$BASE?api_key=$KEY&action=getNumber&service=tg&country=187&maxPrice=0.80"
# → ACCESS_NUMBER:1042:15550001111
curl "$BASE?api_key=$KEY&action=getStatus&id=1042"
# → STATUS_WAIT_CODE … then STATUS_OK:48213
curl "$BASE?api_key=$KEY&action=setStatus&id=1042&status=6"Python
import time, requests
BASE = "https://relysms.pro/stubs/handler_api.php"
KEY = "rs_your_key"
def call(action, **params):
r = requests.get(BASE, params={"api_key": KEY, "action": action, **params}, timeout=30)
r.raise_for_status()
return r.text
answer = call("getNumber", service="tg", country="187", maxPrice="0.80")
if not answer.startswith("ACCESS_NUMBER"):
raise SystemExit(answer) # NO_NUMBERS, NO_BALANCE, …
_, order_id, phone = answer.split(":")
print("number:", phone)
for _ in range(120): # up to 20 minutes, every 10 s
status = call("getStatus", id=order_id)
if status.startswith("STATUS_OK:"):
print("code:", status.split(":", 1)[1])
call("setStatus", id=order_id, status=6)
break
if status == "STATUS_CANCEL":
break # refunded automatically
time.sleep(10)Node.js
const BASE = "https://relysms.pro/stubs/handler_api.php";
const KEY = "rs_your_key";
async function call(action, params = {}) {
const url = new URL(BASE);
url.search = new URLSearchParams({ api_key: KEY, action, ...params });
const res = await fetch(url);
return res.text();
}
const answer = await call("getNumber", { service: "tg", country: "187", maxPrice: "0.80" });
if (!answer.startsWith("ACCESS_NUMBER")) throw new Error(answer);
const [, id, phone] = answer.split(":");
console.log("number:", phone);
for (let i = 0; i < 120; i++) {
const status = await call("getStatus", { id });
if (status.startsWith("STATUS_OK:")) {
console.log("code:", status.slice("STATUS_OK:".length));
await call("setStatus", { id, status: "6" });
break;
}
if (status === "STATUS_CANCEL") break; // refunded automatically
await new Promise((r) => setTimeout(r, 10_000));
}La dirección del servidor, a https://relysms.pro/stubs/handler_api.php; la clave, por la de tu cuenta. Los códigos de servicios y países no cambian.
Las compras por API requieren $20 o más de saldo. La cuenta y la Mini App no tienen ese umbral.
Vuelve solo a tu saldo cuando se cierra la ventana, o al momento si cancelas a los 2 minutos.
Sí, mientras la ventana esté abierta: setStatus=3 y luego getStatus otra vez.
No: todas las compras son reales. Empieza con una combinación barata y prueba tu flujo con un número.
Cuenta → Saldo → API → Emitir una nueva. La anterior deja de funcionar al instante.
La documentación completa en un solo texto para ChatGPT, Claude y otros modelos está en /es/developers.md, y un mapa breve en /llms.txt. Pásale el enlace al modelo y pídele que conecte RelySMS a tu código.
Lee https://relysms.pro/es/developers.md y conecta RelySMS a mi script.