Saltar al contenido principal
placeanalyzerAPI ReferenceGuías

Manejo de Errores

Incluso las mejores integraciones pueden fallar. Esta guía te ayuda a identificar, entender y resolver errores en la API de Place Analyzer.

Códigos de Estado HTTP

La API usa códigos de estado HTTP estándar. Aquí están los más comunes:

CódigoNombreDescripción¿Reintentar?
200OKSolicitud exitosa❌ No
201CreatedRecurso creado exitosamente❌ No
400Bad RequestDatos inválidos en la solicitud❌ No (corregir datos)
401UnauthorizedAPI Key inválida o faltante❌ No (corregir API Key)
404Not FoundRecurso no encontrado❌ No (verificar URLs)
429Too Many RequestsLímite de rate excedido✅ Sí (con backoff)
500Internal Server ErrorError interno del servidor✅ Sí (temporal)

Estructura de Respuesta de Error

Todos los errores siguen una estructura JSON consistente:

{
  "errorCode": "VALIDATION_ERROR",
  "message": "Descripción legible del error",
  "details": {
    "field": "property.propertyType",
    "provided": "INVALID",
    "expected": ["Terreno", "Casa", "Duplex", "Departamento", "Deposito", "Tinglado", "Oficina", "Local Comercial", "Propiedad rural", "Casa quinta", "Edificio"]
  },
  "timestamp": "2025-01-15T10:30:00Z",
  "requestId": "req-123456"
}

Campos importantes:

  • errorCode: Código específico del error (ver catálogo abajo)
  • message: Descripción en español del error
  • details: Información adicional para debugging
  • timestamp: Cuándo ocurrió el error
  • requestId: ID único para soporte técnico

Catálogo de Códigos de Error

🔐 Errores de Autenticación

INVALID_API_KEY

  • Descripción: La API Key proporcionada no es válida
  • Causa común: API Key mal escrita o expirada
  • Solución: Verificar API Key en el dashboard
{
  "errorCode": "INVALID_API_KEY",
  "message": "La API Key proporcionada no es válida",
  "details": {
    "providedKey": "xxx",
    "expectedFormat": "PA-XXXX-XXXX"
  }
}

MISSING_API_KEY

  • Descripción: No se proporcionó API Key
  • Causa común: Header faltante
  • Solución: Incluir -H "X-API-KEY: tu_api_key"

API_KEY_EXPIRED

  • Descripción: La API Key ha expirado
  • Causa común: Key antigua
  • Solución: Generar nueva key en dashboard

INSUFFICIENT_PERMISSIONS

  • Descripción: La API Key no tiene permisos para esta operación
  • Causa común: Key de sandbox usada en producción
  • Solución: Verificar entorno (sandbox vs producción)

✅ Errores de Validación

VALIDATION_ERROR

  • Descripción: Datos inválidos en la solicitud
  • Causa común: Campos faltantes o formato incorrecto
  • Solución: Revisar y corregir los datos enviados
{
  "errorCode": "VALIDATION_ERROR",
  "message": "Errores de validación en la solicitud",
  "details": {
    "errors": [
      {
        "field": "latitude",
        "message": "El valor debe estar entre -90 y 90",
        "provided": 91
      },
      {
        "field": "property.propertyType",
        "message": "Debe ser uno de: Terreno, Casa, Duplex, Departamento, Deposito, Tinglado, Oficina, Local Comercial, Propiedad rural, Casa quinta, Edificio",
        "provided": "INVALID"
      },
      {
        "field": "property.m2Covered",
        "message": "El área cubierta (m2Covered) es requerida para Departamentos"
      }
    ]
  }
}

Campos de validación comunes:

Coordenadas:

  • latitude: debe estar entre -90 y 90
  • longitude: debe estar entre -180 y 180

Propiedad:

  • propertyType: debe ser uno de los valores permitidos (Terreno, Casa, Duplex, Departamento, Deposito, Tinglado, Oficina, Local Comercial, Propiedad rural, Casa quinta, Edificio)
  • m2Land, m2Built, m2Covered, m2SemiCovered: cuando se envían, deben ser >= 0
  • La obligatoriedad de m2Land, m2Built, m2Covered, m2SemiCovered, propertyAge y propertyCondition depende de propertyType (ver Avalúos individuales)

Mensajes de campos requeridos por tipo:

  • Terreno: "El área del terreno (m2Land) es requerida para Terrenos"
  • Departamento: "El área cubierta (m2Covered) es requerida para Departamentos", "El área semicubierta (m2SemiCovered) es requerida para Departamentos", "La antigüedad (propertyAge) es requerida para Departamentos"
  • Demás tipos: "El área del terreno (m2Land) es requerida", "El área construida (m2Built) es requerida", "La antigüedad (propertyAge) es requerida", "El estado de conservación (propertyCondition) es requerido"

🔍 Errores de Recurso No Encontrado

REQUEST_NOT_FOUND

  • Descripción: El requestCode no existe
  • Causa común: requestCode mal escrito o nunca existió
  • Solución: Verificar que el requestCode sea correcto
{
  "errorCode": "REQUEST_NOT_FOUND",
  "message": "No se encontró la solicitud con el código proporcionado",
  "details": {
    "providedCode": "PA-2025-INVALID",
    "suggestion": "Verifica que el código sea correcto"
  }
}

RESULT_NOT_AVAILABLE

  • Descripción: El resultado no está disponible aún
  • Causa común: Avalúo aún en proceso (PENDING_PROCESSING)
  • Solución: Esperar y consultar nuevamente
{
  "errorCode": "RESULT_NOT_AVAILABLE",
  "message": "El resultado no está disponible aún",
  "details": {
    "requestCode": "PA-2025-001234",
    "currentStatus": "PENDING_PROCESSING",
    "suggestion": "Espera a que el estado sea COMPLETED"
  }
}

PROPERTY_NOT_FOUND

  • Descripción: La propiedad no existe
  • Causa común: propertyId inválido
  • Solución: Verificar el propertyId

📊 Errores de Rate Limiting

RATE_LIMIT_EXCEEDED

  • Descripción: Has excedido el límite de requests
  • Causa común: Demasiadas consultas en poco tiempo
  • Solución: Implementar backoff exponencial
{
  "errorCode": "RATE_LIMIT_EXCEEDED",
  "message": "Has excedido el límite de requests por minuto",
  "details": {
    "currentLimit": 100,
    "requestsInWindow": 105,
    "resetTime": "2025-01-15T10:31:00Z",
    "retryAfter": 60
  }
}

🖥️ Errores del Servidor

INTERNAL_SERVER_ERROR

  • Descripción: Error interno del servidor
  • Causa común: Problemas temporales del servidor
  • Solución: Reintentar con backoff exponencial

SERVICE_UNAVAILABLE

  • Descripción: Servicio temporalmente no disponible
  • Causa común: Mantenimiento o sobrecarga
  • Solución: Reintentar más tarde

Estrategias de Manejo de Errores

1. Reintentos Inteligentes

class ApiClient {
  async request(url, options, maxRetries = 3) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        const response = await fetch(url, options);

        if (response.ok) {
          return response.json();
        }

        const error = await response.json();

        // No reintentar errores de validación
        if (response.status === 400 || response.status === 401 || response.status === 404) {
          throw new Error(`${error.errorCode}: ${error.message}`);
        }

        // Reintentar errores del servidor
        if (attempt === maxRetries) {
          throw new Error(`Error después de ${maxRetries} intentos: ${error.message}`);
        }

        // Backoff exponencial
        const delay = Math.pow(2, attempt) * 1000;
        await new Promise(resolve => setTimeout(resolve, delay));

      } catch (error) {
        if (attempt === maxRetries) {
          throw error;
        }
      }
    }
  }
}

2. Manejo Específico por Error

async function handleValuationRequest(requestData, apiKey) {
  try {
    const response = await apiClient.post('/valuation-request', requestData, apiKey);
    return response;
  } catch (error) {
    switch (error.message.split(':')[0]) {
      case 'VALIDATION_ERROR':
        console.log('Datos inválidos:', error.details);
        // Mostrar formulario de corrección
        break;

      case 'INVALID_API_KEY':
        console.log('API Key inválida, redirigir a login');
        // Redirigir a página de login
        break;

      case 'RATE_LIMIT_EXCEEDED':
        console.log('Rate limit excedido, mostrar mensaje de espera');
        // Mostrar mensaje de espera
        break;

      default:
        console.log('Error inesperado:', error.message);
        // Error genérico
    }
  }
}

3. Logging y Monitoreo

class ErrorLogger {
  static logError(error, context = {}) {
    const errorInfo = {
      timestamp: new Date().toISOString(),
      errorCode: error.errorCode,
      message: error.message,
      details: error.details,
      context: context,
      userAgent: navigator.userAgent,
      url: window.location.href
    };

    // Enviar a servicio de logging
    console.error('API Error:', errorInfo);

    // En producción, enviar a servicio como Sentry
    // Sentry.captureException(error, { extra: errorInfo });
  }
}

Ejemplos Prácticos

Manejo de Rate Limiting

async function handleRateLimit() {
  const response = await fetch('/api/valuation-request', {
    headers: { 'X-API-KEY': API_KEY }
  });

  if (response.status === 429) {
    const error = await response.json();
    const resetTime = new Date(error.details.resetTime);
    const waitTime = resetTime.getTime() - Date.now();

    console.log(`Rate limit excedido. Esperar ${Math.ceil(waitTime / 1000)} segundos`);

    await new Promise(resolve => setTimeout(resolve, waitTime));
    return await makeRequest(); // Reintentar
  }
}

Validación antes de enviar

function validateValuationRequest(data) {
  const errors = [];
  const property = data.property || {};

  if (data.latitude == null || data.latitude < -90 || data.latitude > 90) {
    errors.push({ field: 'latitude', message: 'Debe estar entre -90 y 90' });
  }

  if (data.longitude == null || data.longitude < -180 || data.longitude > 180) {
    errors.push({ field: 'longitude', message: 'Debe estar entre -180 y 180' });
  }

  const validTypes = [
    'Terreno', 'Casa', 'Duplex', 'Departamento', 'Deposito', 'Tinglado',
    'Oficina', 'Local Comercial', 'Propiedad rural', 'Casa quinta', 'Edificio'
  ];
  if (!property.propertyType || !validTypes.includes(property.propertyType)) {
    errors.push({
      field: 'property.propertyType',
      message: `Debe ser uno de: ${validTypes.join(', ')}`
    });
  }

  // Campos condicionales según propertyType (ejemplos):
  // Terreno → m2Land
  // Departamento → m2Covered, m2SemiCovered, propertyAge
  // Demás tipos → m2Land, m2Built, propertyAge, propertyCondition

  return errors;
}

Monitoreo y Alertas

Métricas importantes a monitorear:

  1. Tasa de errores por endpoint
  2. Tiempo de respuesta promedio
  3. Rate limits alcanzados
  4. Errores de autenticación

Dashboard de ejemplo:

// Enviar métricas a tu sistema de monitoreo
function trackApiMetrics(endpoint, status, responseTime, errorCode = null) {
  analytics.track('api_request', {
    endpoint: endpoint,
    status: status,
    responseTime: responseTime,
    errorCode: errorCode,
    timestamp: new Date().toISOString()
  });
}

Soporte Técnico

Si no puedes resolver un error:

  1. Guarda el requestId de la respuesta de error
  2. Incluye el requestId en tu consulta de soporte
  3. Proporciona el código que estás usando
  4. Describe qué esperabas que pasara
// Ejemplo de reporte de error completo
const errorReport = {
  requestId: error.requestId,
  timestamp: error.timestamp,
  endpoint: '/valuation-request',
  method: 'POST',
  status: 400,
  errorCode: error.errorCode,
  userAgent: navigator.userAgent,
  requestData: requestData // ¡Sin API Key!
};

Conclusión

El manejo proactivo de errores mejora la experiencia del usuario y reduce el soporte técnico. Implementa:

  • ✅ Validación del lado del cliente antes de enviar
  • ✅ Reintentos inteligentes para errores temporales
  • ✅ Logging detallado para debugging
  • ✅ Mensajes de error amigables para usuarios
  • ✅ Monitoreo de métricas de error

¿Sigues teniendo problemas? Consulta nuestro glosario de estados y términos o contacta a soporte con tu requestId.