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 --debugenhttp://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
/apiglobal. 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, devuelve401. No envía headerWWW-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_KEYde la sesión Flask; expira en 30 días; sin refresh (hay que re-loguearse). RotarSECRET_KEYinvalida 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 < 1 → 400 {"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 elUsuarioWeb(conactivo=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(formularioemail+password→ cookie de sesión); el superadmin esPOST /superadmin/login(credenciales de envSUPERADMIN_*). Ninguno emite tokens para la API externa. - Sin CSRF ni rate limiting en los endpoints de Basic Auth.