watsi API

Manejo de errores

Todas las superficies de la API de watsi — servicios Fastify y rutas de API de Next.js — devuelven un envelope de error consistente. Esta página documenta la estructura estándar, todos los códigos de error y las estrategias de reintento recomendadas.

Respuesta de error estándar

Toda respuesta de error tiene el mismo envelope. El campo de nivel superior error siempre es un objeto con code y message:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "email is required",
    "details": {}          // optional — extra context when available
  }
}
CampoTipoDescripción
error.codestringCódigo de error legible por máquina (p. ej. UNAUTHORIZED)
error.messagestringDescripción legible por humanos de lo que salió mal
error.detailsobject?Objeto opcional con errores a nivel de campo o contexto adicional

Códigos de error

EstadoCódigoDescripción
400VALIDATION_ERROREl cuerpo de la solicitud o los parámetros de consulta no pasaron la validación. Revise el mensaje para más detalles.
400BAD_REQUESTLa solicitud está mal formada o no puede procesarse en su estado actual.
401UNAUTHORIZEDCredenciales de autenticación ausentes o inválidas. Incluya una clave de API o sesión válida.
403FORBIDDENEl usuario autenticado no tiene permiso para realizar esta acción.
404NOT_FOUNDEl recurso solicitado no existe o no es accesible.
405METHOD_NOT_ALLOWEDEl método HTTP no es compatible con este endpoint.
409CONFLICTLa solicitud entra en conflicto con el estado actual (p. ej. recurso duplicado).
429RATE_LIMITEDDemasiadas solicitudes. Reduzca el ritmo y reintente después del intervalo Retry-After.
500INTERNAL_ERROROcurrió un error inesperado en el servidor. Reintente con retroceso exponencial.
502EXTERNAL_API_ERRORUn servicio externo (WhatsApp, proveedor de IA) devolvió un error.
503SERVICE_UNAVAILABLEEl servicio no está disponible temporalmente. Reintente tras una breve espera.

Ejemplos de respuestas

Error de validación (400)

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "email is required"
  }
}

No autorizado (401)

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Unauthorized"
  }
}

No encontrado (404)

HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Chat not found"
  }
}

Límite de tasa excedido (429)

HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Retry after 30 seconds."
  }
}

Error interno (500)

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "Internal server error"
  }
}

Estrategias de reintento

Código¿Reintentable?Estrategia
VALIDATION_ERRORNoCorrija los parámetros de la solicitud antes de reintentar.
UNAUTHORIZEDNoRevise su clave de API o vuelva a autenticarse.
FORBIDDENNoVerifique que cuenta con los permisos requeridos (rol de administrador, etc.).
NOT_FOUNDNoVerifique que el ID del recurso exista.
CONFLICTNoEl recurso ya existe. Obtenga el recurso existente o use un identificador diferente.
RATE_LIMITEDEspere la duración indicada en el encabezado Retry-After y luego reintente. Límite predeterminado: 100 sol./min por clave de API.
INTERNAL_ERRORReintente con retroceso exponencial: 1s, 2s, 4s, hasta 3 intentos.
EXTERNAL_API_ERRORUn proveedor externo falló. Reintente con retroceso exponencial.
SERVICE_UNAVAILABLEEl servicio está temporalmente caído. Reintente después de 5–30 segundos.

Manejo de errores en el código

const res = await fetch('https://api.watsi.ai/api/v1/conversations', {
  headers: { Authorization: `Bearer ${apiKey}` },
})

if (!res.ok) {
  const body = await res.json()
  const { code, message } = body.error

  switch (code) {
    case 'RATE_LIMITED':
      const retryAfter = res.headers.get('Retry-After') ?? '30'
      await sleep(Number(retryAfter) * 1000)
      return retry()
    case 'UNAUTHORIZED':
      throw new Error('Invalid API key')
    default:
      throw new Error(`API error [${code}]: ${message}`)
  }
}