Referencia

Gestión de errores

Todas las respuestas de error siguen una única estructura JSON. Usa los códigos de estado HTTP para enrutar tu lógica de gestión de errores, y el campo error para el contexto legible por humanos.

Formato de respuesta de error
json
// Every non-2xx response returns:
{
  "error": "human-readable description of what went wrong"
}

Códigos de error

La tabla a continuación cubre todos los códigos de estado devueltos por Connect Hub. La columna Reintentar indica si el reintento automático es seguro.

CódigoNombreReintentarDescripción
400Bad RequestNOCampos faltantes o inválidos (p. ej. teléfono no en formato E.164, parámetro de cuerpo obligatorio faltante). Corrige tu payload.
401UnauthorizedNOEncabezado x-api-key faltante o inválido. Verifica tu clave de API: no reintentas automáticamente.
402Payment RequiredNOSaldo de cuenta insuficiente. Recarga tu cuenta de Novauth antes de reintentar.
403ForbiddenNOLa clave de API no tiene permiso para realizar esta acción.
404Not FoundNOEl recurso no existe (p. ej. UUID desconocido en /call/flash/{uuid}/cdr). No reintentas.
409ConflictNOSe detectó una operación duplicada o conflictiva (p. ej. reportar webhook dos veces para el mismo UUID).
422Unprocessable EntityNOEspecífico de Telegram: solicitud semánticamente inválida (p. ej. request_id expirado en check-verification-status).
429Too Many RequestsYESLímite de velocidad excedido. Respeta el encabezado Retry-After e implementa retroceso exponencial.
480Temporarily UnavailableYESEl destinatario no está disponible temporalmente (derivado de SIP). Es seguro reintentar tras una breve espera.
482Loop DetectedNOSe detectó un bucle de enrutamiento de solicitud. No reintentas: investiga tu integración.
486Busy HereYESEl destinatario está ocupado. Reintenta tras una espera o cambia a otro canal.
488Not Acceptable HereNOParámetros de solicitud no aceptables (p. ej. codec o formato no admitido). Corrige la solicitud.
500Internal Server ErrorYESFallo inesperado del lado del servidor. Reintenta con retroceso exponencial (máx. 3 intentos).
502Bad GatewayYESEl servicio upstream (operador, gateway) devolvió una respuesta inválida. Reintenta tras una breve espera.
503Service UnavailableYESServicio temporalmente sobrecargado o en mantenimiento. Respeta el encabezado Retry-After si está presente.
603DeclineNOEl destinatario rechazó explícitamente la llamada (derivado de SIP). No reintentas: el usuario rechazó activamente la llamada.

Lógica de reintento

Reintenta solo en los códigos 429, 480, 486, 500, 502, 503. Usa retroceso exponencial comenzando en 500 ms (duplica cada intento). Nunca reintentas automáticamente errores 4xx del cliente: corrige primero la causa raíz.

javascript
async function callWithRetry(fn, { maxAttempts = 3, baseDelay = 500 } = {}) {
  // Safe codes to retry: 429, 500, 502, 503
  const RETRYABLE = new Set([429, 500, 502, 503]);

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fn();

    if (res.ok) return res;

    const { status } = res;

    // Non-retryable — surface error immediately
    if (!RETRYABLE.has(status)) {
      const body = await res.json().catch(() => ({}));
      throw Object.assign(new Error(body.error ?? 'API error'), { status, body });
    }

    if (attempt === maxAttempts) {
      throw Object.assign(new Error('Max retries reached'), { status });
    }

    // Exponential backoff: 500ms, 1000ms, 2000ms …
    const delay = baseDelay * 2 ** (attempt - 1);
    await new Promise(r => setTimeout(r, delay));
  }
}

// Usage
const res = await callWithRetry(() =>
  fetch('https://api.novauth.com/api/v1/connect-hub/call/flash', {
    method: 'POST',
    headers: {
      'x-api-key':    process.env.BETATEL_API_KEY,
      'x-account-id': process.env.BETATEL_ACCOUNT_ID,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ callee: '+14155552671' })
  })
);

Las operaciones idempotentes (comprobaciones de estado GET) pueden reintentarse libremente. Para operaciones POST que crean recursos, comprueba siempre si el recurso ya fue creado antes de reintentar: usa el UUID devuelto para consultar el estado primero.

Cascada de respaldo

Verify Call funciona en la mayoría de las regiones, pero no es universal. Implementa una cascada para que los usuarios siempre reciban su OTP aunque el canal principal falle.

Orden de respaldo recomendado
Verify Call
más rápido
Telegram OTP
si el usuario tiene TG
SMS
universal
Condiciones de activación: Cambia al canal de respaldo cuando el canal principal devuelva un error no reintentable (400, 402, 488, 603) o cuando la sesión de verificación no se informe como Success dentro de una ventana de tiempo configurable (recomendado: 15 s para Verify Call).
javascript
async function sendWithFallback(phone, otp) {
  // 1. Try Verify Call first
  try {
    const flash = await fetch('.../call/flash', {
      method: 'POST',
      headers,
      body: JSON.stringify({ callee: phone })
    });
    if (flash.ok) return { channel: 'flash', ...(await flash.json()) };
  } catch {}

  // 2. Flash failed — fall back to Telegram if user has it
  try {
    const tg = await fetch('.../telegram', {
      method: 'POST',
      headers,
      body: JSON.stringify({ to: phone, code: otp, ttl: 120 })
    });
    if (tg.ok) return { channel: 'telegram', ...(await tg.json()) };
  } catch {}

  // 3. Final fallback: SMS (widest global reach)
  const sms = await fetch('.../sms', {
    method: 'POST',
    headers,
    body: JSON.stringify({ to: phone, text: `Your code: ${otp}` })
  });
  if (!sms.ok) throw new Error('All channels failed');
  return { channel: 'sms', ...(await sms.json()) };
}

Para deshabilitar la cascada en un flujo específico, omite simplemente los bloques try/catch de respaldo y muestra el error directamente al usuario. No existe una configuración de cascada del lado del servidor: la lógica reside completamente en tu código de integración.

Limitación de velocidad

Los límites de velocidad se aplican en la capa del gateway de API. Cuando se alcanza un límite, recibirás una respuesta 429 Too Many Requests. Comprueba el encabezado Retry-After para conocer el tiempo de espera exacto.

Retry-After
Segundos que se deben esperar antes de que se permita la siguiente solicitud.
X-RateLimit-Limit
Número máximo de solicitudes permitidas en la ventana actual.
X-RateLimit-Remaining
Solicitudes restantes en la ventana actual.
X-RateLimit-Reset
Época Unix en la que se restablece la ventana actual.
javascript
const res = await fetch(url, { method: 'POST', headers, body });

if (res.status === 429) {
  const retryAfter = Number(res.headers.get('Retry-After') ?? 1);
  console.warn(`Rate limited — waiting ${retryAfter}s`);
  await new Promise(r => setTimeout(r, retryAfter * 1000));
  // retry the request
}

Errores comunes de integración

Estos son los problemas más frecuentes reportados durante la integración. Consulta esta lista antes de abrir un ticket de soporte.

1
Enviar números de teléfono sin código de país
Usa formato E.164. "+14155552671" y no "4155552671" ni "014155552671".
2
Llamar a la API desde el navegador
Tu clave de API quedará expuesta en el código del lado del cliente. Siempre realiza las llamadas a través de tu servidor backend.
3
No gestionar el error 402 Payment Required
El saldo se agota silenciosamente en producción. Monitorea el saldo de tu cuenta de Novauth y configura alertas.
4
Reintentar errores 400 y 401
Estos son errores del cliente: reintentar desperdicia presupuesto y añade latencia. Corrige primero la causa raíz.
5
Ignorar el TTL de Telegram
Los códigos expiran tras el ttl que especifiques. Si llamas a check-verification-status después de la expiración, obtendrás un error 422.
6
Analizar el cuerpo de Telegram Gateway antes de verificar la firma
Verifica siempre el HMAC sobre los bytes en bruto antes de JSON.parse(). La re-serialización cambia el orden de los bytes.
7
No revocar los códigos de Telegram tras el éxito
Llama a POST /revoke-verification después de una respuesta code_valid exitosa para prevenir ataques de repetición.
8
Usar Verify Call como único canal sin respaldo
Verify Call falla en algunas redes. Implementa siempre un respaldo a SMS o Telegram para flujos críticos.