Skip to content

API Ford (externa)

Ford es la aplicación Flask de gestión de flota (vehículos, peajes, combustible, multas, arriendos, análisis de ruta). Este documento cubre los endpoints pensados para ser llamados por sistemas externos / scripts y la app móvil (no los del panel web, que requieren sesión de navegador).

Repo fuente: ford, branch main.

Cómo conectarse

  • No hay host productivo committed en el repo. Desarrollo: flask run --debug en http://127.0.0.1:5000. En producción corre bajo gunicorn, pero el hostname se configura fuera del repo. Usá <host> como base de tu instancia.
  • Sin prefijo /api global. Los endpoints programáticos viven bajo dos blueprints: /api (datos + cron) y /api/mobile (app móvil).
  • Los errores 500 devuelven JSON para cualquier path /api/* y HTML para el resto → los callers externos deben usar siempre paths /api.

Autenticación

Mecanismo Cómo Variables de entorno Dónde
HTTP Basic Authorization: Basic <base64(user:pass)> API_BASIC_AUTH_USERNAME / API_BASIC_AUTH_PASSWORD /api datos + cron
JWT Bearer Authorization: Bearer <jwt> (HS256) SECRET_KEY (firma el token) /api/mobile/*
Público GET /health
  • Basic Auth (@require_basic_auth): comparación constante-tiempo (hmac.compare_digest). Fail-closed: si las variables no están seteadas, devuelve 401. No envía header WWW-Authenticate → el cliente debe mandar las credenciales proactivamente.
  • ⚠️ Hay dos implementaciones de Basic Auth: el decorador @require_basic_auth (5 endpoints) y un helper inline _require_api_basic_auth() (1 endpoint, /combustible/copec-auto/detalle) que usa otros códigos (401/403/500).
  • JWT móvil: HS256 firmado con el mismo SECRET_KEY de la sesión Flask; expira en 30 días; sin refresh (hay que re-loguearse). Rotar SECRET_KEY invalida todos los tokens móviles al instante.
  • Envelope de respuesta: {"success": true, "data": ...} / {"success": false, "message": ...}.

En el resto del documento, <host> = la base de la instancia.


Healthcheck

GET  <host>/health        # público → {"status":"ok"}

Datos de flota — /api [HTTP Basic]

GET /api/vehiculos-activos

Catálogo liviano de vehículos activos.

200 {"success": true, "data": {"count": N, "vehiculos": [
  {"id","patente","estado","centro_costo","activo"} ]}}

Filtra VehiculoFlota.activo = true, ordenado por patente. (Nota: hoy aún incluye vehículos con estado='baja'.)

GET /api/vehiculos-flota

Dump completo de toda la tabla vehiculos_flota (sin filtro activo): id, patente, marca/modelo/año, centro_costo, zona, ubicacion, proveedor, estado, km, fechas (revisión técnica/SOAP/permiso/extintor), tarjeta de combustible, tag peaje, tracker Navixy/Tuya, etc. Ordenado por patente.

GET /api/asignaciones-vehiculos/<int:meses>

Asignaciones de vehículos cuyo fecha_asignacion cae en los últimos meses meses (meses * 30 días). Ordenado por fecha_asignacion desc.

200 {"success": true, "data": {"count": N, "asignaciones": [
  {"id","vehiculo_id","patente","rut","nombre","cargo","centro_costo",
   "fecha_asignacion","fecha_devolucion","km_entrega","km_devolucion","activa",
   "fecha_vencimiento_licencia", ...} ]}}

meses < 1400 {"message":"meses debe ser mayor a 0"}.


Análisis de ruta y combustible — /api [HTTP Basic]

GET /api/analisis-ruta-cache

Lee resultados de análisis de ruta persistidos en analisis_ruta_mes_dia_cache.

?mes=2026-07            # YYYY-MM (opcional)
&rut=12345678           # RUT de técnico (opcional)
&include_payload=true   # false omite el campo pesado "payload"
&limit=500              # default 500, tope 10000
&offset=0

200 {"success": true, "data": {"count": N, "registros": [...]}}. Si la tabla no existe → 503 {"message":"La tabla analisis_ruta_mes_dia_cache no existe. Ejecuta 'flask db upgrade' primero."}.

GET /api/combustible/copec-auto/detalle [HTTP Basic — helper inline]

Detalle de carga de combustible Copec de los últimos 7 días (EstadoPagoCombustible.fuente = "copec_auto").

200 {"success": true, "data": [
  {"fecha","hora","patente","litros","monto","rut_conductor",
   "numero_tarjeta","comprobante"} ]}

Ordenado por fecha desc, hora desc. ⚠️ Usa el helper inline, así que los códigos de error difieren: 401 sin header, 403 credenciales malas, 500 si el Basic Auth no está configurado en el servidor.


Cron — /api [HTTP Basic]

POST /api/cron/toa-copec

Ejecuta secuencialmente el job mensual de análisis de ruta TOA y luego el sync Copec. Pensado para ser llamado por un scheduler externo cada ~1 hora. Sin body.

200 {"success": true, "toa": {...}, "copec": {...}}        # ambos ok
207 {"success": false, "toa": {...}, "copec": {...}}       # alguno falló

Cada sub-paso está aislado (un fallo no aborta el otro). No hay guarda de idempotencia: llamadas concurrentes corren ambos jobs.


App móvil / BLE — /api/mobile [JWT Bearer]

Gateway para la app móvil (apertura de puertas por Bluetooth/Tuya).

POST /api/mobile/auth/login — emite el JWT (sin auth)

{ "email": "usuario@creafleet.cl", "password": "<plain>" }
  • 400 {"success": false, "message":"Email y contraseña requeridos"} si falta alguno.
  • 401 {"success": false, "message":"Credenciales inválidas"} si no existe el UsuarioWeb (con activo=true) o la clave no calza.
  • 200:
{ "success": true, "token": "<jwt HS256>", "expires_in": 2592000, "nombre": "..." }

El token (válido 30 días) se envía luego como Authorization: Bearer <token>. Claims: sub (UUID del usuario), iat, exp. No hay endpoint de refresh.

GET /api/mobile/ble/credenciales [Bearer]

Lista los dispositivos BLE/Tuya que el usuario puede abrir (DispositivoConfig.apertura_tuya_habilitada = true y local_key presente). Superadmin ve todos; el resto se filtra por permisos.ble_patentes_autorizadas.

200 {"success": true, "dispositivos": [
  {"id","nombre","mac","ios_uuid","local_key","ble_nombre_anunciado",
   "lan_ip","tuya_lan_protocol","lan_dp_indices"} ]}

401 si el token falta/es inválido/expiró o el usuario ya no existe.

POST /api/mobile/ble/aperturas [Bearer]

Registra un intento de apertura de puerta.

{ "dispositivo_id": "...", "exito": true, "error": null }

Inserta en la tabla ble_aperturas (vía SQL parametrizado). Siempre responde 200 {"success": true}los fallos de inserción se loguean pero no se le informan al cliente.


Notas

  • Esta doc cubre sólo la superficie externa/programática (Basic Auth + JWT móvil). Los otros ~215 endpoints de /api/* (vehículos, peajes, combustible, multas, arriendos, análisis, GPS/Tuya, catálogos, etc.) requieren sesión de navegador (Flask-Login) y son el backend AJAX del panel web.
  • El login del panel web es POST /auth/login (formulario email+password → cookie de sesión); el superadmin es POST /superadmin/login (credenciales de env SUPERADMIN_*). Ninguno emite tokens para la API externa.
  • Sin CSRF ni rate limiting en los endpoints de Basic Auth.