Errores

Guía completa de códigos de error y cómo manejarlos.

Errores

Cuando una solicitud falla, la API devuelve un objeto JSON con información sobre el error.

Formato de error

{
  "error": "Descripción del error",
  "code": "CODIGO_ERROR"
}

Códigos HTTP

CódigoSignificadoDescripción
200OKSolicitud exitosa
400Bad RequestParámetros inválidos o faltantes
401UnauthorizedAPI Key faltante o inválida
403ForbiddenSin permisos o límite excedido
404Not FoundRecurso no encontrado
429Too Many RequestsRate limit excedido
500Internal Server ErrorError del servidor
503Service UnavailableServicio temporalmente no disponible

Errores de autenticación (401)

CódigoMensajeSolución
MISSING_API_KEYAPI Key requeridaIncluye el header X-API-KEY
INVALID_API_KEYAPI Key inválidaVerifica que la key sea correcta
EXPIRED_API_KEYAPI Key expiradaGenera una nueva key
DISABLED_API_KEYAPI Key desactivadaContacta soporte
{
  "error": "API Key inválida",
  "code": "INVALID_API_KEY"
}

Errores de límites (403/429)

CódigoMensajeSolución
DAILY_LIMIT_EXCEEDEDLímite diario excedidoEspera hasta mañana o actualiza tu plan
RATE_LIMITEDDemasiadas solicitudesImplementa backoff exponencial
{
  "error": "Has excedido el límite de solicitudes",
  "code": "RATE_LIMITED",
  "retryAfter": 60
}

El campo retryAfter indica los segundos que debes esperar antes de reintentar.

Errores de validación (400)

CódigoMensajeCausa
INVALID_RUCRUC inválidoRUC no tiene 11 dígitos
SEARCH_TOO_SHORTBúsqueda muy cortaTexto menor a 3 caracteres
INVALID_DATE_FORMATFormato de fecha inválidoUsa YYYY-MM-DD
MISSING_FIELDCampo requerido faltanteRevisa el body de la solicitud
{
  "error": "El RUC debe tener 11 dígitos numéricos",
  "code": "INVALID_RUC"
}

Errores de recursos (404)

CódigoMensajeDescripción
NOT_FOUNDContribuyente no encontradoEl RUC no existe en SUNAT
EXCHANGE_RATE_NOT_FOUNDTipo de cambio no disponibleNo hay datos para esa fecha

Errores del servidor (500/503)

CódigoMensajeDescripción
INTERNAL_ERRORError interno del servidorError inesperado
SUNAT_UNAVAILABLEServicio SUNAT no disponibleLos servicios de SUNAT están caídos
DATABASE_ERRORError de base de datosProblema de conexión

Los errores 5xx son temporales. Implementa reintentos con backoff exponencial.

Manejo de errores

Ejemplo en TypeScript

interface ApiError {
  error: string;
  code: string;
  retryAfter?: number;
}

async function consultarApi(endpoint: string) {
  const response = await fetch(`https://api.kipudev.com${endpoint}`, {
    headers: { "X-API-KEY": process.env.KIPUDEV_API_KEY },
  });

  if (!response.ok) {
    const error: ApiError = await response.json();
    
    switch (response.status) {
      case 401:
        throw new Error(`Autenticación fallida: ${error.error}`);
      case 403:
        throw new Error(`Sin permisos: ${error.error}`);
      case 404:
        return null; // Recurso no encontrado
      case 429:
        // Implementar retry después de error.retryAfter segundos
        throw new Error(`Rate limited. Retry en ${error.retryAfter}s`);
      default:
        throw new Error(`Error ${response.status}: ${error.error}`);
    }
  }

  return response.json();
}

Backoff exponencial

async function fetchWithRetry(
  url: string, 
  options: RequestInit,
  maxRetries = 3
) {
  let lastError: Error;
  
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        const data = await response.json();
        const waitTime = data.retryAfter || Math.pow(2, i) * 1000;
        await new Promise(r => setTimeout(r, waitTime));
        continue;
      }
      
      return response;
    } catch (error) {
      lastError = error as Error;
      const waitTime = Math.pow(2, i) * 1000; // 1s, 2s, 4s
      await new Promise(r => setTimeout(r, waitTime));
    }
  }
  
  throw lastError!;
}

Buenas prácticas

  • ✅ Siempre maneja los errores de forma específica
  • ✅ Implementa reintentos para errores temporales (5xx, 429)
  • ✅ Usa backoff exponencial para reintentos
  • ✅ Loggea los errores para debugging
  • ✅ Muestra mensajes amigables al usuario final
  • ❌ No reintentes errores 4xx (excepto 429)
  • ❌ No expongas detalles técnicos al usuario final