Operaciones
Kilometraje (ingesta)

Ingesta de kilometraje

Registra lecturas de kilometraje/telemetría de la flota (ECU del vehículo, odómetro digital). El endpoint es genérico: no asume ningún proveedor de telemetría. Cualquier cliente, con cualquier sistema (FleetMetrics/Pegasus, otro proveedor, o ninguno), escribe acá — el proveedor entra como el valor del campo source_system.

Sobre estos datos corre la regla de mantenimiento por kilometraje: cada vehículo con un plan de mantenimiento activo dispara una alerta cuando su kilometraje acumulado desde el último mantenimiento (o desde la primera lectura, si nunca se registró uno) supera el intervalo configurado.

POST/transportes/sync/vehicle-mileage-readings

Ingesta idempotente de lecturas de kilometraje/telemetría, en lotes de hasta 500.

Caso de uso

Un sistema externo de telemetría (o el poller de Smartfleet contra un proveedor como FleetMetrics/Pegasus) lee periódicamente el contador de kilometraje de cada vehículo, lo normaliza a esta forma y lo envía. Reenviar la misma lectura no duplica: la llave de idempotencia es (tenant, source_system, source_id).

Campos del payload

Raíz

CampoTipoRequeridoDescripción
source_systemstring (≤30)Sistema de origen. Se normaliza a minúsculas.
readingsarrayEntre 1 y 500 ítems. Más de 500 → 400.

Cada lectura

Requeridos

CampoTipoDescripción
source_idstring (≤128)Identificador estable de la lectura. Es la llave de idempotencia — para telemetría de contador (sin evento propio del proveedor), se recomienda un hash del vehículo + la ventana de la corrida, para que reingerir el mismo rango no duplique.
vehicle_source_idstring (≤128)Identificador del vehículo en el sistema de origen (el mismo valor cargado en vehicles.source_id para ese source_system). A diferencia de la ingesta de combustible, este dominio liga por identificador, no por placa.
occurred_atstring ISO 8601Fecha y hora de la lectura con offset UTC explícito (Z o ±HH:MM). Sin offset → 400.
distance_kmnumberKilometraje acumulado del vehículo al momento de la lectura. >= 0 (un vehículo detenido puede seguir reportando).
raw_payloadobjectRegistro original del sistema de origen, para trazabilidad.

Opcionales

CampoTipoDescripción
fuel_level_litersnumberNivel de combustible reportado por el ECU, si el proveedor lo expone.
engine_hoursnumberHoras de motor acumuladas, si el proveedor lo expone.

Respuesta — los cuatro contadores

Los cuatro son disjuntos y suman received.

ContadorSignificado
receivedÍtems recibidos en el lote.
insertedLecturas nuevas que se ligaron a un vehículo por vehicle_source_id.
duplicatesÍtems cuyo source_id ya existía para ese source_system. No es un error: se cuenta y se sigue.
quarantinedLecturas nuevas cuyo vehicle_source_id no coincide con ningún vehículo. No se pierden: se guardan con el vehículo vacío y se pueden religar después.

Request

{
  "source_system": "fleetmetrics",
  "readings": [
    {
      "source_id": "8f1c2e...64-hex",
      "vehicle_source_id": "pegasus-vid-123",
      "occurred_at": "2026-08-26T08:00:00-06:00",
      "distance_km": 128430.500,
      "fuel_level_liters": 42.1,
      "engine_hours": 3120.5,
      "raw_payload": { "vehicle_ecu_dist": 128430500, "vehicle_ecu_tfuel": 42.1 }
    }
  ]
}

Response

{
  "ok": true,
  "code": "SYNC_OK",
  "message": "Sync processed successfully.",
  "data": {
    "received": 20,
    "inserted": 18,
    "duplicates": 1,
    "quarantined": 1
  },
  "meta": {
    "route": "/transportes/sync/vehicle-mileage-readings",
    "method": "PostVehicleMileageReadingsSync",
    "operation": "ingest",
    "source_system": "fleetmetrics"
  }
}

Errores

Todos los errores de validación abortan el lote entero — no hay ingesta parcial.

SituaciónRespuesta
distance_km ausente o negativo400 CAPTURED_ERROR: Validation error: …
source_id o vehicle_source_id ausente o vacío400 CAPTURED_ERROR: Validation error: …
occurred_at sin offset UTC400 CAPTURED_ERROR: Validation error: … (tenant timezone is '…')
occurred_at con una fecha que no existe400 CAPTURED_ERROR: Validation error: occurred_at is not a real calendar date-time.
raw_payload ausente400 CAPTURED_ERROR: Validation error: …
Más de 500 lecturas400 CAPTURED_ERROR: Validation error: …

Cuarentena

Una lectura cuyo vehicle_source_id no existe en el catálogo de vehículos no se rechaza y no se pierde: se guarda con el vehículo vacío y marcada como unmatched_vehicle, con el identificador tal cual llegó. Al cargar vehicles.source_id para ese vehículo (mismo source_system), esas lecturas se pueden religar.

Kilometraje vivo del vehículo

El "km actual" de un vehículo se deriva de la lectura más reciente (MAX(occurred_at)) en esta tabla — nunca de un contador aparte que alguien digite a mano. Sin ninguna lectura, el vehículo simplemente no tiene kilometraje conocido todavía (no se asume 0).

Regla de alerta que corre sobre estos datos

VEHICLE_MAINTENANCE_DUE_BY_MILEAGE — dispara cuando el kilometraje acumulado desde el último mantenimiento registrado (o desde la primera lectura, si nunca hubo uno) supera el interval_km configurado en el plan de mantenimiento del vehículo. Un vehículo sin plan activo nunca dispara esta regla.