Skip to content

Códigos de Respuesta

La API TSALVA produce dos familias de respuesta según de dónde provenga:

  1. Respuestas de los controladores (lógica de negocio): objeto { "status": <boolean>, "msg": <string> }, a veces con campos adicionales (data, codigoServicio, etc.). Se usan en 200, 400, 403, 404 y 500 generados dentro de cada endpoint.
  2. Respuestas del manejador global de errores y rutas del sistema: usadas para errores no controlados, autenticación Basic, timeouts (408), ruta no encontrada (404) y rate limiting (429). Su forma es distinta (error, message, errorId, timestamp).

Los mensajes de negocio están en MAYÚSCULAS

Muchos mensajes msg de los controladores se devuelven en mayúsculas, tal cual aparecen abajo. No dependas del texto exacto para lógica de control; usa el código HTTP y el campo status.

Respuesta Exitosa (200)

Estructura base: { "status": true, "msg": "..." }

CampoTipoDescripción
statusbooleantrue para operaciones exitosas
msgstringMensaje descriptivo del resultado

Ejemplos reales por endpoint:

json
// POST /api/v3/oferta
{
  "status": true,
  "msg": "SE HA RECIBIDO EXITOSAMENTE LA OFERTA DEL SERVICIO"
}

// POST /api/v3/asignacion
{
  "status": true,
  "msg": "SERVICIO HA SIDO ASIGNADO EXITOSAMENTE CENTRAL PRESTADORA ABC"
}

// POST /api/v3/no-asignacion
{
  "status": true,
  "msg": "SE HA RECIBIDO EXITOSAMENTE LA NO ASIGNACIÓN DEL SERVICIO"
}

// POST /api/v3/cancelacion
{
  "status": true,
  "msg": "Se ha efectuado la cancelación del servicio en la central CENTRAL PRESTADORA ABC correctamente."
}

Error de Validación (400)

Estructura: { "status": false, "msg": "..." }

CampoTipoDescripción
statusbooleanfalse
msgstringDescripción específica del error de validación

Ejemplos reales:

json
// POST /api/v3/oferta - falta uuid
{
  "status": false,
  "msg": "NO SE RECIBIÓ EL CAMPO 'uuid', REQUERIDO PARA EJECUTAR LA OFERTA DEL SERVICIO"
}

// POST /api/v3/oferta - falta tipoServicio
{
  "status": false,
  "msg": "EL CAMPO 'tipoServicio' ES REQUERIDO PARA REALIZAR LA OFERTA DEL SERVICIO"
}

// POST /api/v3/queries/history - falta línea de negocio
{
  "status": false,
  "msg": "La línea de negocio es requerida."
}

No Autorizado (401)

Se produce por credenciales inválidas o faltantes. La forma del cuerpo depende del validador:

json
// Basic Auth (mayoría de endpoints) - pasa por el manejador global
{
  "error": true,
  "message": "Las credenciales de acceso no son correctas.",
  "errorId": "err_1720353600000_a1b2c3d4e",
  "timestamp": "2026-07-07T12:00:00.000Z"
}

// PUT /api/v3/aceptacion (API key)
{
  "status": false,
  "msg": "La clave de acceso no es correcta.",
  "timestamp": "2026-07-07T12:00:00.000Z"
}

Ver todos los mensajes exactos en Autenticación.

Prohibido (403)

Puede provenir de una restricción de negocio del controlador o de una restricción de acceso del validador.

json
// Restricción de negocio (controlador)
{
  "status": false,
  "msg": "La oferta que se intenta cancelar aún no ha sido asignada, por lo tanto no es posible procesar la cancelación del servicio."
}

// Basic Auth - usuario inactivo (manejador global)
{
  "error": true,
  "message": "El estado del usuario de API es 'INACTIVO'.",
  "errorId": "err_1720353600000_f5g6h7i8j",
  "timestamp": "2026-07-07T12:00:00.000Z"
}

// Basic Auth - sin permiso al endpoint (manejador global)
{
  "error": true,
  "message": "No tiene permiso de acceso a este endpoint.",
  "errorId": "err_1720353600000_k9l0m1n2o",
  "timestamp": "2026-07-07T12:00:00.000Z"
}

No Encontrado (404)

Hay dos casos:

a) Recurso no encontrado dentro de un endpoint (controlador):

json
{
  "status": false,
  "msg": "OFERTA NO ENCONTRADA"
}

b) Ruta inexistente (manejador de ruta no encontrada del servidor):

json
{
  "error": "Ruta no encontrada",
  "message": "La ruta solicitada no existe en esta API",
  "documentation": "https://...",
  "suggestion": "Revisa la documentación para conocer las rutas disponibles",
  "available_versions": {
    "v1": "/api/v1 (redirige automáticamente a v3)",
    "v2": "/api/v2 (redirige automáticamente a v3)",
    "v3": "/api/v3 (versión actual)"
  },
  "requested_path": "/api/v3/ruta-inexistente",
  "method": "GET",
  "timestamp": "2026-07-07T12:00:00.000Z"
}

Tiempo de Espera Excedido (408)

Cuando una petición supera el timeout de conexión (60 segundos), el manejador global responde:

json
{
  "error": true,
  "message": "La petición ha excedido el tiempo de espera",
  "errorId": "err_1720353600000_p3q4r5s6t",
  "timestamp": "2026-07-07T12:00:00.000Z"
}

Demasiadas Solicitudes (429)

El rate limiting está activo únicamente en el endpoint de login (/api/v3/users/login): 5 intentos por 15 minutos por IP. El límite global de API está definido pero no habilitado. Cuerpo real:

json
{
  "error": "Demasiadas solicitudes",
  "message": "Límite de 5 solicitudes excedido",
  "retryAfter": 900,
  "timestamp": "2026-07-07T12:00:00.000Z"
}

Además, se envían los headers informativos X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset.

Error Interno (500)

Un error controlado dentro de un endpoint devuelve el formato de controlador:

json
{
  "status": false,
  "msg": "OCURRIÓ UN ERROR AL PROCESAR LA NO ASIGNACIÓN DEL SERVICIO"
}

Un error no controlado pasa por el manejador global y devuelve:

json
{
  "error": true,
  "message": "Error interno del servidor",
  "errorId": "err_1720353600000_u7v8w9x0y",
  "timestamp": "2026-07-07T12:00:00.000Z"
}

El errorId identifica el incidente en los logs del servidor; inclúyelo si reportas el problema a soporte.

Códigos de Estado HTTP

CódigoNombreCuándo se usa
200OKOperación completada correctamente
400Bad RequestDatos faltantes, formato inválido, validación
401UnauthorizedCredenciales/clave inválidas o faltantes
403ForbiddenUsuario inactivo, sin permiso al endpoint o restricción de negocio
404Not FoundRecurso no encontrado o ruta inexistente
408Request TimeoutLa petición superó el timeout de 60 s
429Too Many RequestsRate limiting (solo login)
500Internal Server ErrorFallos del sistema, base de datos, etc.

Respuestas Especiales por Endpoint

POST /api/v3/asignacion-directa

Respuesta exitosa con datos adicionales:

json
{
  "status": true,
  "msg": "EL SERVICIO DE GRÚA LIVIANA HA SIDO ASIGNADO EXITOSAMENTE A CENTRAL PRESTADORA ABC, CÓDIGO DE SERVICIO: GOT00356 - CÓDIGO DE SOLICITUD: ABO0036",
  "codigoServicio": "GOT00356",
  "codigoSolicitud": "ABO0036"
}

GET /api/v3/types

Devuelve directamente un array de tipos de servicio:

json
[
  {
    "id": 1,
    "type": "Conductor elegido",
    "required_origin": true,
    "required_destination": false
  },
  {
    "id": 2,
    "type": "Grúa Liviana",
    "required_origin": true,
    "required_destination": true
  }
]

POST /api/v3/queries/history

Respuesta con datos históricos (status, data, msg):

json
{
  "status": true,
  "data": [
    {
      "idServicio": "ABC123456789",
      "estado": "Completado",
      "prestador": "Central Norte SAS"
    }
  ],
  "msg": "Datos obtenidos correctamente"
}

GET /api/v3/queries/history-options

Respuesta con opciones de filtrado:

json
{
  "status": true,
  "data": {
    "taskStatus": [{ "id": 1, "name": "Pendiente" }],
    "serviceStatus": [{ "id": 1, "name": "Activo" }],
    "businessNits": [{ "nit": "900000001", "name": "Empresa ABC SAS" }]
  }
}

Manejo de Errores

Estrategia Recomendada

javascript
async function handleApiResponse(response) {
  // Verificar estado HTTP
  if (!response.ok) {
    if (response.status === 401) throw new Error('Credenciales inválidas');
    if (response.status === 403) throw new Error('Acceso denegado');
    if (response.status === 429) throw new Error('Límite de peticiones excedido');
    if (response.status >= 500) throw new Error('Error del servidor, reintentar más tarde');
  }

  const data = await response.json();

  // Los controladores exponen 'status'; los errores del sistema exponen 'error'
  if (data.status === false || data.error === true) {
    throw new Error(data.msg || data.message || 'Error desconocido');
  }

  return data;
}

Reintentos para Errores 5xx

javascript
async function apiCallWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      if (response.status >= 500 && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000; // Backoff exponencial
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      return await handleApiResponse(response);
    } catch (error) {
      if (attempt === maxRetries) throw error;
    }
  }
}

Buenas Prácticas

  • Verifica el código HTTP y, según la familia de respuesta, el campo status (controladores) o error (sistema).
  • Guarda el errorId de los errores del sistema para reportarlos a soporte.
  • Implementa reintentos para errores 5xx con backoff exponencial.

Importante

Los mensajes de texto pueden cambiar. No dependas del texto exacto para lógica de negocio; usa los códigos HTTP y los campos status/error.

Tsalva API - Documentación desarrollada por RobPixels