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…