FleetOS
OpenAPIWeb

API de FleetOS

Todo lo que ves en el CRM está disponible por API REST en JSON: vehículos, maquinaria, conductores, documentos, mantenimiento, combustible, costes, incidencias, alertas, turnos, checklists y más. La especificación completa está en OpenAPI 3.1 y se genera a partir de los mismos validadores que usa el servidor, así que no puede quedarse desfasada.

URL base: https://fleetos.cybernetix.es/api/v1. Disponible desde el plan Business.

Autenticación

Crea una clave en el CRM (Integraciones → Claves de API) y envíala en cada petición. Las claves pueden ser de solo lectura o de lectura y escritura, y nunca administran usuarios, ajustes ni facturación ni descargan documentos.

curl 'https://fleetos.cybernetix.es/api/v1/vehicles?limite=5' \
  -H 'Authorization: Bearer fk_live_XXXXXXXXXXXXXXXXXXXX'

Errores

Todos los errores tienen el mismo formato y un código estable que puedes tratar en tu código:

HTTP/1.1 422
{ "error": { "codigo": "validacion", "mensaje": "Datos no válidos.", "detalles": { "importe": ["Number must be ≥ 0"] } } }

Códigos habituales: 401 no_autenticado / api_key_invalida, 402 limite_plan / plan_insuficiente, 403 prohibido / clave_solo_lectura, 404 no_encontrado, 409 duplicado / solape, 422 validacion, 429 limite_peticiones.

Paginación, orden y filtros

Los listados devuelven { datos, total, pagina, limite }. Parámetros comunes: pagina, limite (hasta 1000), q (búsqueda), orden, dir (asc/desc), desde y hasta (fechas) y los filtros propios de cada recurso. Fechas en formato YYYY-MM-DD; instantes en ISO 8601 UTC.

Idempotencia

Envía la cabecera Idempotency-Key (8–100 caracteres) en los POST. Si reintentas la misma petición con la misma clave, recibes la respuesta original (con Idempotent-Replayed: true) sin crear un duplicado. Si reutilizas la clave con un cuerpo distinto, recibes 422 idempotency_conflicto. Las claves caducan a las 24 horas.

Límites de peticiones

Hasta 300 peticiones por minuto y por clave. Al superarlo recibes 429; las cabeceras RateLimit-* indican cuánto falta para reiniciar el contador.

Webhooks

Recibe un POST en tu URL (https pública) cuando algo cambia. Cada evento sigue la forma recurso.created | updated | deleted y existen alert.created y alert.escalated. Puedes suscribirte con comodín (vehicles.*).

POST /tu-endpoint
X-FleetOS-Event: vehicles.created
X-FleetOS-Delivery: 5b0d…-uuid
X-FleetOS-Signature: t=1731240000,v1=9f8a…hex

{ "id": "5b0d…", "evento": "vehicles.created", "creado": "2026-11-10T12:00:00Z", "tenant_id": 1, "datos": { "id": 42, "matricula": "1234-ABC" } }

Verifica siempre la firma: es el HMAC-SHA256 de `${t}.${cuerpo_sin_modificar}` con el secreto del webhook. Rechaza entregas con t de hace más de 5 minutos para evitar repeticiones.

// Node.js
import crypto from 'node:crypto';
function verificar(cuerpoCrudo, cabecera, secreto) {
  const [, t, v1] = /^t=(\d+),v1=([0-9a-f]+)$/.exec(cabecera) ?? [];
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const esperado = crypto.createHmac('sha256', secreto).update(`${t}.${cuerpoCrudo}`).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(esperado));
}
# Python
import hmac, hashlib, time
def verificar(cuerpo: bytes, cabecera: str, secreto: str) -> bool:
    partes = dict(p.split('=') for p in cabecera.split(','))
    if abs(time.time() - int(partes['t'])) > 300: return False
    esperado = hmac.new(secreto.encode(), f"{partes['t']}.".encode() + cuerpo, hashlib.sha256).hexdigest()
    return hmac.compare_digest(partes['v1'], esperado)

Responde con cualquier 2xx en menos de 8 segundos. Si falla, reintentamos a 1 min, 5 min, 30 min, 2 h y 6 h. Un webhook que acumula 30 fallos seguidos se desactiva solo.

Referencia

Cargando…