API para recibir códigos por correo: ejemplo en Python y Node.js
Si pruebas flujos de registro, onboarding o recuperación de contraseña, tarde o temprano necesitas leer un código de verificación (OTP) desde tu propio código. Con la API REST de OTPGmail eso se reduce a tres llamadas: alquilar un buzón real @gmail.com o @icloud.com, consultar el pedido hasta que llegue el código y cancelar si ya no lo necesitas. Esta guía muestra un ejemplo completo en Python y otro en Node.js.
Necesitas una cuenta (registrarte no cuesta nada), saldo y tu clave de API, que encontrarás en la página Cuenta de la app. Consulta la documentación completa de la API.
Cómo funciona la API en tres llamadas
Cada cuenta tiene una clave de API personal que empieza por og_ y no caduca; si la regeneras, la anterior deja de funcionar al instante. Envíala en la cabecera Authorization: Bearer <clave> o en el parámetro ?api_key=.
POST /v1/orderscon el cuerpo{"service": "git", "domain": "gmail.com"}. Devuelve una lista de pedidos, uno por buzón, conorderId,email,statusyotp[].domaines opcional (por defectogmail.com) yquantitypermite hasta 200 buzones por llamada.GET /v1/orders/{id}cada 3–5 segundos. Cuando llega el código, aparece enotp[]y el estado pasa acompleted. El código más reciente siempre va al final de la lista.POST /v1/orders/{id}/cancelsi quieres abandonar antes de que llegue un código: se reembolsa el 100 %. Si no haces nada, el pedido se cancela solo al terminar el tiempo de espera (25 minutos como máximo) con el mismo reembolso.
Dos detalles importantes al crear el pedido. Envía siempre una cabecera Idempotency-Key con un UUID nuevo por pedido; si la llamada se corta y la repites, usa la misma clave y la API te devolverá el pedido ya creado en lugar de cobrarte otro. Y pon un tiempo de espera de unos 15 segundos en tu cliente: la API espera a que se asigne el buzón y, en momentos de mucha demanda, puede tardar varios segundos en responder.
Ejemplo en Python
Usa requests y no urllib a secas: según la documentación, el agente de usuario por defecto de urllib es rechazado con un error 403.
import time
import uuid
import requests
HOST = "otpgmail.net"
API_KEY = "og_TU_CLAVE" # página «Cuenta» de la app
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
def alquilar(servicio, dominio="gmail.com"):
"""Crea un pedido y devuelve el primer buzón asignado."""
r = requests.post(
f"https://{HOST}/v1/orders",
json={"service": servicio, "domain": dominio},
headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
timeout=15,
)
cuerpo = r.json()
if not cuerpo.get("success"):
raise RuntimeError(cuerpo["error"]["code"])
return cuerpo["data"][0] # data es una lista: un elemento por buzón
def esperar_codigo(pedido_id, espera_max=600, intervalo=4):
"""Consulta el pedido hasta que llega un código."""
limite = time.time() + espera_max
while time.time() < limite:
r = requests.get(f"https://{HOST}/v1/orders/{pedido_id}", headers=HEADERS, timeout=15)
pedido = r.json()["data"]
if pedido["otp"]:
return pedido["otp"][-1]["code"] # el más reciente va al final
if pedido["status"] == "cancelled":
return None # se canceló solo y el importe volvió al saldo
time.sleep(intervalo)
# Abandonamos antes que la API: cancelar devuelve el 100 % si no llegó ningún código
requests.post(f"https://{HOST}/v1/orders/{pedido_id}/cancel", headers=HEADERS, timeout=15)
return None
pedido = alquilar("git") # "git" es GitHub; los códigos de servicio están en GET /v1/services
print("Dirección:", pedido["email"])
# ... aquí tu prueba envía el formulario de registro con pedido["email"] ...
codigo = esperar_codigo(pedido["orderId"])
print("Código:", codigo or "no llegó")
Empieza a consultar después de enviar el formulario: antes de eso el servicio todavía no ha mandado nada. En el ejemplo se usa GitHub, que suele enviar el código rápido; su página de alquiler para GitHub muestra la espera típica de los últimos 30 días.
Ejemplo en Node.js
Con Node.js 18 o superior, fetch ya viene incluido. Este ejemplo intenta primero un buzón de iCloud, que suele ser más barato, y cambia a Gmail si no está disponible.
import { randomUUID } from "node:crypto";
const HOST = "otpgmail.net";
const headers = { Authorization: `Bearer ${process.env.OTPGMAIL_API_KEY}` };
async function alquilar(servicio, dominio = "gmail.com") {
const res = await fetch(`https://${HOST}/v1/orders`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": randomUUID() },
body: JSON.stringify({ service: servicio, domain: dominio }),
signal: AbortSignal.timeout(15000), // la asignación puede tardar unos segundos
});
const cuerpo = await res.json();
if (!cuerpo.success) throw new Error(cuerpo.error.code);
return cuerpo.data[0];
}
async function esperarCodigo(pedidoId, esperaMaxMs = 600000, intervaloMs = 4000) {
const limite = Date.now() + esperaMaxMs;
while (Date.now() < limite) {
const res = await fetch(`https://${HOST}/v1/orders/${pedidoId}`, { headers });
const { data: pedido } = await res.json();
if (pedido.otp.length) return pedido.otp[pedido.otp.length - 1].code; // el más reciente
if (pedido.status === "cancelled") return null;
await new Promise((r) => setTimeout(r, intervaloMs));
}
await fetch(`https://${HOST}/v1/orders/${pedidoId}/cancel`, { method: "POST", headers });
return null;
}
const pedido = await alquilar("dr", "icloud.com").catch((e) => {
if (["DOMAIN_UNAVAILABLE", "NO_MAILS_AVAILABLE", "OUT_OF_STOCK"].includes(e.message)) return alquilar("dr", "gmail.com");
throw e;
});
console.log("Dirección:", pedido.email);
console.log("Código:", (await esperarCodigo(pedido.orderId)) ?? "no llegó");
dr es el código de ChatGPT, un servicio que a veces tarda un par de minutos en enviar el código; por eso conviene no bajar demasiado esperaMaxMs.
Errores que debes manejar
Todas las respuestas de error tienen la forma {"success": false, "error": {"code": "...", "message": "..."}}. Los códigos más habituales:
NO_MAILS_AVAILABLEyOUT_OF_STOCK: no hay buzones para ese servicio en ese momento. No se cobra nada; reintenta más tarde o cambia dedomain.DOMAIN_UNAVAILABLE: el servicio no ofrece ese tipo de buzón o está pausado. Repite congmail.com.INSUFFICIENT_BALANCE: recarga saldo; con USDT o USDC tienes el paso a paso en la guía de recarga.VALIDATION_ERROR: revisa el cuerpo de la petición y el código de servicio contraGET /v1/services.ORDER_NOT_CANCELLABLE: el pedido ya recibió un código, así que no se puede cancelar ni reembolsar.RATE_LIMITED(HTTP 429): superaste el límite, que por defecto es de 20 peticiones por segundo y 900 por minuto. Espera los segundos que indica la cabeceraRetry-After.
Un mismo servicio puede venderse desde varias fuentes (almacenes) con precios y reglas distintas. Si no envías warehouse, el pedido va a la fuente por defecto; con "warehouse": 99 la API prueba de la más barata a la más cara hasta encontrar stock, y si todas están agotadas responde ALL_WAREHOUSES_EXHAUSTED sin cobrar nada. Las reglas de cada fuente están en offers[] de GET /v1/services.
Consejos para pruebas de QA
- Un buzón por prueba. Así cada ejecución es independiente y puedes registrar el
orderIdjunto al resultado del test. - No pidas más de un código por formulario sin esperar: muchos servicios solo aceptan el último.
- Cancela en el teardown los pedidos que no recibieron código; recuperas el 100 % al momento.
- Códigos adicionales: si el servicio envía más de uno por buzón (por ejemplo, registro y luego un nuevo dispositivo), aparecerán al final de
otp[]durante el periodo del pedido sin costo extra; muchos servicios envían uno solo. - Guarda la clave en una variable de entorno y no la compartas: es personal.
Usa la API para fines legítimos, como pruebas de tus propios productos o cuentas de prueba, y respeta las condiciones de cada plataforma. Si prefieres partir de código ya hecho, hay clientes de ejemplo en Python, Node.js, PHP, C# y curl en el repositorio público de OTPGmail, en inglés.
Preguntas frecuentes
¿Dónde consigo la clave de API?
En la página Cuenta de la app, después de crear tu cuenta. Puedes regenerarla cuando quieras; la anterior deja de funcionar al instante.
¿Cada cuánto debo consultar el pedido?
Cada 3–5 segundos mientras el estado sea waiting_code. Es suficiente para recibir el código enseguida sin acercarte a los límites de peticiones.
¿Puedo alquilar varios buzones en una sola llamada?
Sí, con quantity hasta 200 por llamada. La respuesta trae un elemento por buzón en data.
¿Puedo comprar cuentas de Gmail por la API?
Sí. Además de alquilar buzones y leer códigos, la API permite comprar cuentas de Gmail de vida corta con los endpoints /v1/mail-shop (listar productos, crear el pedido y consultar el resultado); los detalles están en la documentación de la API.
Antes de programar, si quieres entender el producto, lee alquilar un Gmail para recibir códigos.
