API para integraciones
Viajes
Viajes de trabajo de los conductores (libro de viajes).
En esta página
Lista los viajes (libro o sincronización incremental)
POST/movimientos/viajes/list
- Permiso
lectura
Devuelve los viajes de la empresa. Tiene dos modos.
Libro (sin updatedSince ni cursor): las líneas activas (sin anuladas ni descartadas),
en orden cronológico: día (tripDate), hora de inicio (los registrados a mano, sin hora, van
después de los iniciados ese día) y orden de alta (tripId). order: "desc" es el reverso exacto de
asc. limit (1-500) recorta la serie y, sin él, vienen todas: { "order": "desc", "limit": 1 }
es el último viaje. Para el libro de un mes, from y to (incluidos). La respuesta solo trae trips.
Sincronización incremental (con updatedSince o cursor): todo lo que cambió, también los
viajes anulados y descartados (active: false) y los que están en curso, en orden de cambio
(updatedAt, tripId) y por páginas (limit 1-200, por defecto 200). order no se admite.
- Primera página:
{ "updatedSince": "2026-10-13T08:00:00Z" }más los filtros que quieras. Entrega los viajes cuyoupdatedAtes posterior aupdatedSince(exclusivo) y como mucho igual asyncedUntil, que fija esta primera página: la hora de la base de datos menos 60 s, oupdatedSincesi es posterior (nunca hacia atrás). - Siguientes páginas, mientras
nextCursorno seanull: el mismo cuerpo con"cursor": "<nextCursor>". El cursor es opaco, manda sobreupdatedSince(que puedes volver a mandar o quitar) y lleva el mismosyncedUntil. Repite los filtros en cada página: el cursor no los guarda. - Al acabar (
nextCursor: null): guardasyncedUntiltal cual (UTC con microsegundos) y empieza la siguiente sincronización con{ "updatedSince": "<syncedUntil>" }. UsasyncedUntil, no el mayorupdatedAtque hayas visto (updatedAtva en milisegundos).
Dentro de un recorrido no hay duplicados ni huecos: un viaje que cambia mientras recorres las
páginas queda fuera de ese syncedUntil y llega en la siguiente sincronización. Un cambio tarda
como poco 60 s en aparecer; lo que registra tu propia integración ya lo tienes en la respuesta de
viajes/save.
updatedAt cambia con cualquier escritura de la fila: alta, corrección, anulación, descarte,
fin, firma del cliente, consumo o recorrido GPS. No cambia por el coste derivado (depende de los
gastos y las lecturas del mes), ni por el nombre del conductor, la matrícula o el nombre de la
categoría: si necesitas esas cifras al día, vuelve a pedir el mes en modo libro con from/to.
Los viajes que la retención fiscal purga (más de 4 años) no se anuncian.
Filtros (en los dos modos; se combinan): from y to (YYYY-MM-DD, incluidos, from ≤ to),
userId (conductor), vehicleId y status. Un userId o vehicleId que no es de tu empresa da
lista vacía, nunca 404.
Con clave API se ve toda la empresa (la clave actúa como el owner que la creó). Cada viaje es un
ViajesTrip con su coste y su semáforo calculados en el momento de la lectura y con apiKeyId (la
clave con la que se dio de alta, o null si lo registró una persona). La lista no trae
attendedByName ni signedAt (solo hasSignature): pídelos con viajes/get.
Errores propios
422 invalid_input:error.fieldstrae todos los campos erróneos a la vez.invalidenfrom,to(también si es anterior afrom),userId,vehicleId,status,limit(fuera de 1-500, o de 1-200 al sincronizar),order(cualquier valor al sincronizar),updatedSince(sin zona horaria, fecha imposible o anterior a 1970) ycursor(no lo emitió el servidor);unexpected_fielden cualquier otra clave. Sinfieldssi el cuerpo no es un objeto JSON.
Petición
Cuerpo opcional
Opcional. Sin cuerpo equivale a {} (el libro entero de la empresa).
Todo opcional. Con updatedSince o cursor es una sincronización incremental.
fromstring (date) | nullDesde este día (
YYYY-MM-DD, incluido).tostring (date) | nullHasta este día (
YYYY-MM-DD, incluido). No anterior afrom.userIdinteger | string | nullSolo los viajes de este conductor.
integer: mínimo
1integer: máximo9007199254740991string: patrón^[1-9][0-9]{0,15}$vehicleIdinteger | string | nullSolo los viajes de este vehículo.
integer: mínimo
1integer: máximo9007199254740991string: patrón^[1-9][0-9]{0,15}$statusstring | nullSolo los viajes en este estado.
recorded: registrado a mano a posteriori (web, app o API).in_progress: iniciado en la app y aún sin finalizar.finished: iniciado y finalizado en la app.Valores:
recordedin_progressfinishedorderstring | nullSolo en modo libro (con
updatedSinceocursor, cualquier valor esinvalid).Valores:
ascdescPor defecto:asclimitinteger | nullModo libro: 1-500; sin él, todas. Sincronización: 1-200, por defecto 200.
Mínimo
1Máximo500updatedSincestring | nullEmpieza una sincronización: viajes con
updatedAtposterior a este instante. ISO 8601 con zona (Zo±hh:mm); segundos opcionales y hasta 6 decimales; desde 1970. Ejemplos:2026-10-13T08:00:00Z,2026-10-13T10:00+02:00, elsyncedUntilde la sincronización anterior.Patrón:
^\d{4}-\d{2}-\d{2}T([01]\d|2[0-3]):[0-5]\d(:[0-5]\d(\.\d{1,6})?)?(Z|[+-](0\d|1[0-4]):[0-5]\d)$cursorstring | nullEl
nextCursorde la página anterior, tal cual (opaco). Manda sobreupdatedSince.De 1 a 200 caracteresPatrón:
^[A-Za-z0-9_-]+$
Ejemplo: Libro de octubre de un vehículo
curl -sS -X POST "https://app.flotadoc.com/api/movimientos/viajes/list" \
-H "Authorization: Bearer $FLOTADOC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "2026-10-01",
"to": "2026-10-31",
"vehicleId": 7
}'
Otro ejemplo: Último viaje de un conductor
{
"userId": 15,
"order": "desc",
"limit": 1
}
Otro ejemplo: Sincronización, primera página
{
"updatedSince": "2026-10-13T08:00:00Z",
"limit": 200
}
Otro ejemplo: Sincronización, página siguiente
{
"limit": 200,
"cursor": "eyJ2IjoxLCJ1IjoiMjAyNi0xMC0xM1QwOTo1ODo0MS4wMDQxMTJaIiwidCI6IjIwMjYtMTAtMTNUMDk6MTI6MDMuNTEyMzMxWiIsImkiOjQxMn0"
}
Respuesta
200
Viajes del filtro. En modo libro solo trips; en una sincronización, además nextCursor y
syncedUntil.
Cabeceras
X-Request-Idstring (uuid)Id de la petición en el historial de la empresa (para soporte).
dataobjecttripsViajesTrip[]Un viaje con su coste y su semáforo, calculados en el momento de la lectura.
nextCursorstring | nullopcionalSolo en una sincronización. Cursor de la página siguiente;
nullsi no hay más.syncedUntilstringopcionalSolo en una sincronización. Hasta dónde llega este recorrido (UTC con microsegundos, el mismo en todas sus páginas). Al acabar, es el
updatedSincede la siguiente sincronización.Patrón:
^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z$
Ejemplo de respuesta: Modo libro
{
"data": {
"trips": [
{
"tripId": 398,
"tenantId": 42,
"userId": 18,
"userName": "Iván Comercial",
"vehicleId": 7,
"vehiclePlate": "1234ABC",
"status": "finished",
"tripDate": "2026-10-08",
"startedAt": "2026-10-08T07:05:12.318Z",
"endedAt": "2026-10-08T07:41:55.902Z",
"origin": "Polígono Cantabria, Logroño",
"destination": "Calle Portales 20, Logroño",
"originLat": 42.481203,
"originLng": -2.462011,
"originAccuracyM": 8,
"destinationLat": 42.466517,
"destinationLng": -2.44538,
"destinationAccuracyM": 12.5,
"distanceKm": 25.1,
"routeKm": 24.6,
"routeDurationMin": 31,
"odometerKm": 48210,
"reason": "Visita comercial a Distribuciones Ebro",
"reasonCategoryId": 1,
"reasonCategoryName": "Visita a cliente",
"costBasis": "fuel",
"kmRate": null,
"amount": null,
"consumptionL100km": 6.2,
"trackKm": 25.4,
"trackGapKm": 0,
"hasSignature": true,
"correctedAt": null,
"active": true,
"updatedAt": "2026-10-08T07:45:02.114Z",
"apiKeyId": null,
"cost": 3.87,
"costKind": "justified",
"costPending": null,
"provisionalCost": null,
"justifiedAmount": 3.87,
"monthTicketsAmount": 186.4,
"monthOdometerKm": 1210,
"monthShareKm": 1210,
"estimatedLiters": 1.56,
"consumptionCost": 2.43,
"fuelPricePerLiter": 1.559,
"fuelPriceSource": "month",
"fuelPriceTicketDate": null,
"alertLevel": "ok",
"alertReasons": []
}
]
}
}
Ejemplo de respuesta: Sincronización con más páginas
{
"data": {
"trips": [
{
"tripId": 412,
"tenantId": 42,
"userId": 15,
"userName": "Bea Conductora",
"vehicleId": 9,
"vehiclePlate": "5678DEF",
"status": "recorded",
"tripDate": "2026-10-09",
"startedAt": null,
"endedAt": null,
"origin": "Calle Mayor 1, Logroño",
"destination": "Polígono Cantabria, Logroño",
"originLat": null,
"originLng": null,
"originAccuracyM": null,
"destinationLat": null,
"destinationLng": null,
"destinationAccuracyM": null,
"distanceKm": 7.4,
"routeKm": null,
"routeDurationMin": null,
"odometerKm": null,
"reason": "Revisión de la instalación del cliente",
"reasonCategoryId": 3,
"reasonCategoryName": "Servicio técnico o instalación",
"costBasis": "km_rate",
"kmRate": 0.26,
"amount": 1.92,
"consumptionL100km": null,
"trackKm": null,
"trackGapKm": null,
"hasSignature": false,
"correctedAt": null,
"active": false,
"updatedAt": "2026-10-13T09:12:03.512Z",
"apiKeyId": 5,
"cost": 1.92,
"costKind": "allowance",
"costPending": null,
"provisionalCost": null,
"justifiedAmount": null,
"monthTicketsAmount": null,
"monthOdometerKm": null,
"monthShareKm": null,
"estimatedLiters": null,
"consumptionCost": null,
"fuelPricePerLiter": null,
"fuelPriceSource": null,
"fuelPriceTicketDate": null,
"alertLevel": "warn",
"alertReasons": [
"manual"
]
}
],
"nextCursor": "eyJ2IjoxLCJ1IjoiMjAyNi0xMC0xM1QwOTo1ODo0MS4wMDQxMTJaIiwidCI6IjIwMjYtMTAtMTNUMDk6MTI6MDMuNTEyMzMxWiIsImkiOjQxMn0",
"syncedUntil": "2026-10-13T09:58:41.004112Z"
}
}
Además, las respuestas comunes: 401, 403, 404, 422, 429, 503.
Ficha de un viaje
POST/movimientos/viajes/get
- Permiso
lectura
Ficha de un viaje activo de la empresa: el viaje completo con attendedByName y signedAt
(firma del cliente), el coste y el semáforo calculados en el momento, y integration: la clave API
con la que se dio de alta (apiKeyId, nombre y prefijo visible, también si la clave ya está
revocada) o null si lo registró una persona. Si el nombre de la clave no se puede leer,
integration llega con name y prefix a null y la ficha sale igual.
Un viaje anulado o descartado responde 404: su historial sigue en viajes/history y la
sincronización de viajes/list lo entrega con active: false.
Errores propios
404 trip_not_found: no existe, es de otra empresa o está anulado o descartado.422 invalid_input:fields.tripId=requiredoinvalid; cualquier otra clave,unexpected_field.
Petición
Cuerpo obligatorio
tripIdinteger | stringobligatorioIdentificador. Entero positivo; también se admite como texto de dígitos (
"412").integer: mínimo
1integer: máximo9007199254740991string: patrón^[1-9][0-9]{0,15}$
Ejemplo
curl -sS -X POST "https://app.flotadoc.com/api/movimientos/viajes/get" \
-H "Authorization: Bearer $FLOTADOC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tripId": 412
}'
Respuesta
200
La ficha del viaje.
Cabeceras
X-Request-Idstring (uuid)Id de la petición en el historial de la empresa (para soporte).
dataobjecttripobjectIncluye todos los campos de
ViajesTripDetail.integrationViajesIntegration | nullClave API con la que se dio de alta el viaje (también si ya está revocada), o
nullsi lo registró una persona.nameyprefixsonnullsi no se pudieron leer.
Ejemplo de respuesta
{
"data": {
"trip": {
"tripId": 412,
"tenantId": 42,
"userId": 15,
"userName": "Bea Conductora",
"vehicleId": 9,
"vehiclePlate": "5678DEF",
"status": "recorded",
"tripDate": "2026-10-09",
"startedAt": null,
"endedAt": null,
"origin": "Calle Mayor 1, Logroño",
"destination": "Polígono Cantabria, Logroño",
"originLat": null,
"originLng": null,
"originAccuracyM": null,
"destinationLat": null,
"destinationLng": null,
"destinationAccuracyM": null,
"distanceKm": 7.4,
"routeKm": null,
"routeDurationMin": null,
"odometerKm": null,
"reason": "Revisión de la instalación del cliente",
"reasonCategoryId": 3,
"reasonCategoryName": "Servicio técnico o instalación",
"costBasis": "km_rate",
"kmRate": 0.26,
"amount": 1.92,
"consumptionL100km": null,
"trackKm": null,
"trackGapKm": null,
"hasSignature": false,
"correctedAt": null,
"active": true,
"updatedAt": "2026-10-09T16:20:11.482Z",
"apiKeyId": 5,
"cost": 1.92,
"costKind": "allowance",
"costPending": null,
"provisionalCost": null,
"justifiedAmount": null,
"monthTicketsAmount": null,
"monthOdometerKm": null,
"monthShareKm": null,
"estimatedLiters": null,
"consumptionCost": null,
"fuelPricePerLiter": null,
"fuelPriceSource": null,
"fuelPriceTicketDate": null,
"alertLevel": "warn",
"alertReasons": [
"manual"
],
"attendedByName": null,
"signedAt": null,
"integration": {
"apiKeyId": 5,
"name": "ERP Contabilidad",
"prefix": "fd_live_Ab12"
}
}
}
}
Además, las respuestas comunes: 401, 403, 404, 422, 429, 503.
Historial de versiones de un viaje
POST/movimientos/viajes/history
- Permiso
lectura
Versiones selladas de un viaje cuando la empresa tiene activados los registros inalterables:
alta (create, también al finalizar un viaje iniciado en la app), correcciones (correct, también
de la firma del cliente), anulación (void) y versiones técnicas del recorrido GPS (technical:
puntos que llegaron tarde; sin autor, sin motivo y sin instantánea). Cada versión trae quién y
cuándo, el motivo del cambio, la instantánea fiscal después del cambio, las huellas de sus
ficheros (firma y recorrido), qué campos de la instantánea cambiaron respecto a la anterior y su
huella en la cadena (entryHash).
Alcanza también un viaje anulado o descartado. versions es [] si el viaje es anterior a la
activación, si la empresa no tiene el ajuste o si el viaje no ha llegado al libro (en curso o
descartado). Como mucho 500 versiones por viaje, de la primera a la última.
integration es la de viajes/get. El alta que hace una integración la firma (author) el owner
que creó la clave.
Una versión con redacted: true ha perdido su contenido o no se entiende: es una alteración, y
movimientos/integridad/verify da la cadena por rota.
Errores propios
404 trip_not_found: no existe o es de otra empresa.422 invalid_input:fields.tripId=requiredoinvalid; cualquier otra clave,unexpected_field.
Petición
Cuerpo obligatorio
tripIdinteger | stringobligatorioIdentificador. Entero positivo; también se admite como texto de dígitos (
"412").integer: mínimo
1integer: máximo9007199254740991string: patrón^[1-9][0-9]{0,15}$
Ejemplo
curl -sS -X POST "https://app.flotadoc.com/api/movimientos/viajes/history" \
-H "Authorization: Bearer $FLOTADOC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tripId": 412
}'
Respuesta
200
Las versiones del viaje, de la primera a la última.
Cabeceras
X-Request-Idstring (uuid)Id de la petición en el historial de la empresa (para soporte).
dataobjecttripIdintegerMínimo
1integrationViajesIntegration | nullClave API con la que se dio de alta el viaje (también si ya está revocada), o
nullsi lo registró una persona.nameyprefixsonnullsi no se pudieron leer.versionsViajesTripVersion[]Hasta 500 elementos
Ejemplo de respuesta
{
"data": {
"tripId": 412,
"integration": {
"apiKeyId": 5,
"name": "ERP Contabilidad",
"prefix": "fd_live_Ab12"
},
"versions": [
{
"seq": 141,
"version": 1,
"change": "create",
"author": {
"userId": 3,
"name": "Marta Titular"
},
"recordedAt": "2026-10-09T16:20:11.482Z",
"reason": null,
"snapshot": {
"status": "recorded",
"tripDate": "2026-10-09",
"userId": 15,
"vehicleId": 9,
"startedAt": null,
"endedAt": null,
"origin": "Calle Mayor 1, Logroño",
"originLat": null,
"originLng": null,
"destination": "Polígono Cantabria, Logroño",
"destinationLat": null,
"destinationLng": null,
"distanceKm": 7.4,
"odometerKm": null,
"reason": "Revisión de la instalación del cliente",
"reasonCategory": "Servicio técnico o instalación",
"costBasis": "km_rate",
"kmRate": 0.26,
"amount": 1.92,
"attendedByName": null,
"signedAt": null,
"signatureSha256": null
},
"files": [],
"changed": [],
"entryHash": "1b7d0c9e5a3f4b2d8e6c1a0f9b8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e",
"redacted": false
},
{
"seq": 187,
"version": 2,
"change": "void",
"author": {
"userId": 3,
"name": "Marta Titular"
},
"recordedAt": "2026-10-13T09:12:03.512Z",
"reason": "Viaje duplicado en el ERP",
"snapshot": {
"status": "recorded",
"tripDate": "2026-10-09",
"userId": 15,
"vehicleId": 9,
"startedAt": null,
"endedAt": null,
"origin": "Calle Mayor 1, Logroño",
"originLat": null,
"originLng": null,
"destination": "Polígono Cantabria, Logroño",
"destinationLat": null,
"destinationLng": null,
"distanceKm": 7.4,
"odometerKm": null,
"reason": "Revisión de la instalación del cliente",
"reasonCategory": "Servicio técnico o instalación",
"costBasis": "km_rate",
"kmRate": 0.26,
"amount": 1.92,
"attendedByName": null,
"signedAt": null,
"signatureSha256": null
},
"files": [],
"changed": [],
"entryHash": "77a04c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b",
"redacted": false
}
]
}
}
Además, las respuestas comunes: 401, 403, 404, 422, 429, 503.
Lista las categorías de motivo
POST/movimientos/viajes/reasons-list
- Permiso
lectura
Categorías activas del catálogo de motivos de la empresa, en orden de alta (las seis por defecto,
primero). Sirven para reasonCategoryId en viajes/save: el motivo del viaje (reason) es siempre
un texto libre obligatorio y la categoría es opcional.
Si la empresa aún no tiene ninguna categoría (ni activa ni borrada), la primera consulta crea las
seis por defecto (isDefault: true): Visita a cliente, Reunión, Servicio técnico o instalación,
Compra de material, Gestión administrativa y Formación. Una categoría por defecto renombrada sigue
siendo isDefault. El catálogo lo mantiene el owner en la web; no se edita por la API.
Errores propios
422 invalid_input: cualquier clave del cuerpo esunexpected_field.
Petición
Cuerpo opcional
Opcional. Sin cuerpo equivale a {}.
object
Ejemplo
curl -sS -X POST "https://app.flotadoc.com/api/movimientos/viajes/reasons-list" \
-H "Authorization: Bearer $FLOTADOC_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
Respuesta
200
Las categorías activas.
Cabeceras
X-Request-Idstring (uuid)Id de la petición en el historial de la empresa (para soporte).
dataobjectreasonCategoriesViajesReasonCategory[]
Ejemplo de respuesta
{
"data": {
"reasonCategories": [
{
"reasonCategoryId": 1,
"name": "Visita a cliente",
"isDefault": true,
"updatedAt": "2026-10-06T10:00:00.000Z"
},
{
"reasonCategoryId": 2,
"name": "Reunión",
"isDefault": true,
"updatedAt": "2026-10-06T10:00:00.000Z"
},
{
"reasonCategoryId": 3,
"name": "Servicio técnico o instalación",
"isDefault": true,
"updatedAt": "2026-10-06T10:00:00.000Z"
},
{
"reasonCategoryId": 4,
"name": "Compra de material",
"isDefault": true,
"updatedAt": "2026-10-06T10:00:00.000Z"
},
{
"reasonCategoryId": 5,
"name": "Gestión administrativa",
"isDefault": true,
"updatedAt": "2026-10-06T10:00:00.000Z"
},
{
"reasonCategoryId": 6,
"name": "Formación",
"isDefault": true,
"updatedAt": "2026-10-06T10:00:00.000Z"
},
{
"reasonCategoryId": 9,
"name": "Entrega de pedidos",
"isDefault": false,
"updatedAt": "2026-10-07T12:31:44.208Z"
}
]
}
}
Además, las respuestas comunes: 401, 403, 404, 422, 429, 503.
Registra un viaje para un conductor o corrige uno
POST/movimientos/viajes/save
- Permiso
registros - Admite
Idempotency-Key
Alta (sin tripId) de un viaje ya hecho, a nombre de un conductor, o corrección completa
(con tripId) de una línea del libro. Responde 200 con el viaje tal como ha quedado, con su coste
y su semáforo.
Alta con clave API
driverUserIdes obligatorio: el conductor a cuyo nombre queda el viaje (userIdde la respuesta). Tiene que ser un conductor de la empresa: roluseruowner(también un invitado que aún no ha entrado), no desactivado; un gestor no conduce. Puede ser el propio owner que creó la clave.vehicleId: un vehículo activo de la empresa (404vehicle_not_foundsi no existe, es de otra empresa o está de baja) que el conductor pueda usar con sus reglas: unuser, los vehículos variables y los fijos donde figura como conductor; un owner, todos (si no, 422fields.driverUserId: vehicle_not_allowed).- Nace con
status: recorded(registrado a mano: avisomanualdel semáforo), sin horas de inicio ni fin, y guarda la clave (apiKeyId): la web lo muestra como «Registrado por la integración «nombre»». El autor del sello de integridad y de la auditoría es el owner de la clave.
Km, tarifa e importe (los fija el servidor; no se mandan):
distanceKmson los km declarados: el dato fiscal.routeKm/routeDurationMin(ruta estimada) solo lo respaldan; si los declarados se desvían más de un 25 % derouteKm, el semáforo avisa (route_deviation).costBasisse copia del régimen del vehículo: propio →km_rate; de empresa →fuel.km_rate:kmRatese copia de la tarifa por km de la empresa en la misma escritura yamount=ROUND(distanceKm × kmRate, 2)lo calcula la base de datos.cost=amount.fuel: sin tarifa ni importe (kmRateyamountnull).costes la parte justificada de los tickets de energía del mes del vehículo (monthTicketsAmount × distanceKm ÷ monthShareKm), calculada al leer; queda pendiente mientras falte la lectura del cuentakilómetros del mes o no cuadre.consumptionL100kmsolo se guarda enfuel(enkm_ratese ignora).
Corrección (con tripId), como el owner en la web:
- Reemplaza todos los campos editables: los opcionales ausentes o
nullse guardan vacíos, salvoconsumptionL100km(ausente conserva el que tenga;nulllo quita). Lee antes el viaje conviajes/gety manda el conjunto completo. - No cambian nunca el conductor (si mandas
driverUserId, tiene que ser el que ya tiene: si no, 422immutable), el estado, las horas de inicio y fin ni el origen de la línea (apiKeyId). En un viajefinished(iniciado y finalizado en la app),tripDatey las coordenadas son evidencia: se ignoran los del cuerpo. - Un vehículo distinto tiene que ser un vehículo activo de la empresa (404
vehicle_not_found); su régimen pasa a ser la base de coste. Si el vehículo no cambia, la línea conserva su base y su tarifa aunque después hayan cambiado el régimen del vehículo o la tarifa de la empresa. El vehículo nuevo lo tiene que poder usar el conductor de la línea con sus reglas, como en el alta (unuser, los variables y los fijos donde conduce; un owner, todos): si no, 422fields.vehicleId: vehicle_not_allowed, sin cambiar nada. - La categoría que el viaje ya tenía vale aunque se haya borrado del catálogo; una nueva tiene que estar activa.
- Si cambia un dato fiscal (día, vehículo, origen, destino, km, motivo o categoría),
correctedAtpasa a ser ahora (avisocorrected). - Un viaje en curso no se corrige (409
trip_in_progress): lo finaliza o lo descarta el conductor en la app.
Mes cerrado. Un alta no entra en un mes cerrado del vehículo, y una corrección no sale del mes
cerrado de la línea ni entra en otro (vehículo y día de destino): 409 period_closed con
error.periods = [{ "vehicleId": 7, "month": "2026-09" }]. Hay que reabrir el mes en la web
(movimientos/cierres).
Registros inalterables. Si la empresa los tiene activados, el alta sella una versión create y
la corrección una correct, que exige changeReason (422 reason_required, sin escribir
nada). Sin el ajuste, changeReason se acepta y no se guarda: mándalo siempre al corregir.
Cuenta en solo lectura. Con la prueba o el contrato vencidos, la cuenta pendiente del primer
pago, suspendida o cancelada: 423 account_read_only (error.reason: account, pending_payment o
suspended).
Idempotencia. Manda una Idempotency-Key distinta por cada viaje que registras (por ejemplo, el
id del viaje en tu sistema): un reintento por un corte de red no duplica el viaje. Cualquier
respuesta que no sea 5xx (también un 409 o un 422) queda guardada 24 h con esa clave y se repite
tal cual: después de corregir el problema (reabrir el mes, arreglar un campo), reintenta con otra
Idempotency-Key.
Orden de comprobaciones: puerta de la API → cuerpo objeto JSON (422) → cuenta que escribe (423)
→ campos (422 invalid_input) → alta: driverUserId presente (422), vehículo (404), conductor (422
not_found / vehicle_not_allowed), categoría (404), mes cerrado (409) · corrección: viaje (404),
en curso (409), conductor (422 immutable), vehículo nuevo (404 y 422 vehicle_not_allowed),
categoría nueva (404), mes cerrado (409) y, si se puede escribir, motivo con registros inalterables
(422 reason_required).
Errores propios
404 trip_not_found: corrección de un viaje que no existe, es de otra empresa o está anulado o descartado.404 vehicle_not_found: el vehículo no existe, es de otra empresa o está de baja.404 reason_category_not_found: la categoría no existe, es de otra empresa o está borrada (salvo la que el viaje ya tenía).409 trip_in_progress: corrección de un viaje en curso.409 period_closed: mes cerrado del vehículo; los meses enerror.periods.422 invalid_input:error.fieldscon todos los campos erróneos:required,invalid,too_long,in_future(tripDateposterior a hoy en Madrid) ounexpected_field(una clave que no admite, p. ej.userId,kmRate,amount,costBasis,statusoapiKeyId). ParadriverUserId, además, y en solitario:required(alta sin él),not_found(no es conductor activo de la empresa),vehicle_not_allowed(no puede usar ese vehículo) eimmutable(corrección con otro conductor). ParavehicleId, en solitario:vehicle_not_allowed(corrección a un vehículo que el conductor de la línea no puede usar).422 reason_required: corrección con registros inalterables activos y sinchangeReason.423 account_read_only: la cuenta no admite registros (error.reason).
Petición
Cabeceras
Idempotency-KeystringClave de idempotencia de la escritura (opcional, recomendada). Vale 24 horas por clave API: la misma
Idempotency-Keycon la misma ruta y el mismo cuerpo exacto devuelve la respuesta guardada conIdempotent-Replayed: truesin volver a ejecutar la operación. Con otro cuerpo u otra ruta:409 idempotency_conflict; si la primera aún está en curso:409 idempotency_in_progress. Una respuesta 5xx no se guarda (se puede reintentar). Mal formada:422 invalid_idempotency_key.Patrón:
^[A-Za-z0-9_-]{1,100}$
Cuerpo obligatorio
Sin tripId: alta (con clave API, driverUserId obligatorio). Con tripId: corrección completa
(los opcionales ausentes o null se guardan vacíos, salvo consumptionL100km). Los textos se
recortan; los números van como número JSON ("12.5" no vale) y los ids admiten también texto de
dígitos.
tripIdinteger | string | nullAusente o
null, alta. Un id, corrección de ese viaje.integer: mínimo
1integer: máximo9007199254740991string: patrón^[1-9][0-9]{0,15}$driverUserIdinteger | string | nullConductor del viaje:
useruowneractivo (o invitado) de la empresa que pueda usarvehicleId. Obligatorio en un alta con clave API. En una corrección es opcional y, si llega, tiene que ser el conductor que ya tiene el viaje (immutable).integer: mínimo
1integer: máximo9007199254740991string: patrón^[1-9][0-9]{0,15}$tripDatestring (date)obligatorioDía del viaje (
YYYY-MM-DD), no posterior a hoy en Madrid. En un viajefinishedse ignora al corregir.vehicleIdinteger | stringobligatorioIdentificador. Entero positivo; también se admite como texto de dígitos (
"412").integer: mínimo
1integer: máximo9007199254740991string: patrón^[1-9][0-9]{0,15}$originstringobligatorioSalida (1-200 caracteres tras recortar espacios).
De 1 a 200 caracteresPatrón:
\SdestinationstringobligatorioDestino (1-200 caracteres tras recortar espacios).
De 1 a 200 caracteresPatrón:
\SoriginLatnumber | nullLatitud de la salida (WGS84). Con
originLng: los dos o ninguno (requireden el que falte). Se guarda con 6 decimales. En un viajefinishedse ignora al corregir.Mínimo
-90Máximo90originLngnumber | nullLongitud de la salida (WGS84). Pareja de
originLat.Mínimo
-180Máximo180destinationLatnumber | nullLatitud del destino (WGS84). Con
destinationLng, los dos o ninguno.Mínimo
-90Máximo90destinationLngnumber | nullLongitud del destino (WGS84). Pareja de
destinationLat.Mínimo
-180Máximo180distanceKmnumberobligatorioKm declarados (el dato fiscal), con 2 decimales como mucho.
Mayor que
0Máximo99999.99routeKmnumber | nullKm de la ruta estimada (2 decimales como mucho).
Mayor que
0Máximo99999.99routeDurationMininteger | nullDuración de la ruta estimada, en minutos.
Mínimo
0Máximo10080odometerKminteger | nullLectura del cuentakilómetros.
Mínimo
0Máximo9999999reasonstringobligatorioMotivo del viaje, texto libre obligatorio (1-500 caracteres tras recortar espacios).
De 1 a 500 caracteresPatrón:
\SreasonCategoryIdinteger | string | nullCategoría activa del catálogo (
viajes/reasons-list). Opcional.integer: mínimo
1integer: máximo9007199254740991string: patrón^[1-9][0-9]{0,15}$consumptionL100kmnumber | nullConsumo (l/100 km), 2 decimales como mucho. Solo se guarda en un vehículo de empresa (
fuel); enkm_ratese ignora. En una corrección, ausente conserva el que tenga ynulllo quita.Mayor que
0Máximo99.99changeReasonstring | nullMotivo de la corrección (hasta 500 caracteres tras recortar; en blanco = sin motivo). Obligatorio al corregir si la empresa tiene registros inalterables (
reason_required); un alta lo ignora. No esreason(el motivo del viaje).Hasta 500 caracteres
Ejemplo: Alta de un viaje para un conductor
curl -sS -X POST "https://app.flotadoc.com/api/movimientos/viajes/save" \
-H "Authorization: Bearer $FLOTADOC_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-d '{
"driverUserId": 15,
"vehicleId": 9,
"tripDate": "2026-10-09",
"origin": "Calle Mayor 1, Logroño",
"destination": "Polígono Cantabria, Logroño",
"distanceKm": 7.4,
"reason": "Revisión de la instalación del cliente",
"reasonCategoryId": 3
}'
Otro ejemplo: Corrección completa de un viaje
{
"tripId": 412,
"driverUserId": 15,
"vehicleId": 9,
"tripDate": "2026-10-09",
"origin": "Calle Mayor 1, Logroño",
"destination": "Polígono Cantabria, Logroño",
"distanceKm": 9.8,
"reason": "Revisión de la instalación del cliente",
"reasonCategoryId": 3,
"changeReason": "Km mal tecleados en el ERP"
}
Respuesta
200
El viaje tal como ha quedado (alta o corrección).
Cabeceras
X-Request-Idstring (uuid)Id de la petición en el historial de la empresa (para soporte).
Idempotent-Replayedstringtruesi es la respuesta guardada de una petición anterior con la mismaIdempotency-Key.Valores:
true
dataobjecttripViajesTripDetailEl viaje con los datos de la firma del cliente (
attendedByName,signedAt).
Ejemplo de respuesta
{
"data": {
"trip": {
"tripId": 412,
"tenantId": 42,
"userId": 15,
"userName": "Bea Conductora",
"vehicleId": 9,
"vehiclePlate": "5678DEF",
"status": "recorded",
"tripDate": "2026-10-09",
"startedAt": null,
"endedAt": null,
"origin": "Calle Mayor 1, Logroño",
"destination": "Polígono Cantabria, Logroño",
"originLat": null,
"originLng": null,
"originAccuracyM": null,
"destinationLat": null,
"destinationLng": null,
"destinationAccuracyM": null,
"distanceKm": 7.4,
"routeKm": null,
"routeDurationMin": null,
"odometerKm": null,
"reason": "Revisión de la instalación del cliente",
"reasonCategoryId": 3,
"reasonCategoryName": "Servicio técnico o instalación",
"costBasis": "km_rate",
"kmRate": 0.26,
"amount": 1.92,
"consumptionL100km": null,
"trackKm": null,
"trackGapKm": null,
"hasSignature": false,
"correctedAt": null,
"active": true,
"updatedAt": "2026-10-09T16:20:11.482Z",
"apiKeyId": 5,
"cost": 1.92,
"costKind": "allowance",
"costPending": null,
"provisionalCost": null,
"justifiedAmount": null,
"monthTicketsAmount": null,
"monthOdometerKm": null,
"monthShareKm": null,
"estimatedLiters": null,
"consumptionCost": null,
"fuelPricePerLiter": null,
"fuelPriceSource": null,
"fuelPriceTicketDate": null,
"alertLevel": "warn",
"alertReasons": [
"manual"
],
"attendedByName": null,
"signedAt": null
}
}
}
Además, las respuestas comunes: 401, 403, 404, 409, 422, 423, 429, 503.
Anula un viaje
POST/movimientos/viajes/delete
- Permiso
registros - Admite
Idempotency-Key
Anula una línea del libro, como el owner en la web. Es un borrado lógico: la fila se conserva 4
años (art. 66 LGT), deja de salir en el libro y en viajes/get (404) y la sincronización de
viajes/list la entrega con active: false. La firma y el recorrido GPS se conservan.
- Un viaje en curso aún no es una línea del libro: no se anula (409
trip_in_progress); lo descarta el conductor en la app. - Una línea de un mes cerrado del vehículo no se anula (409
period_closed, conerror.periods): hay que reabrir el mes en la web. - Registros inalterables: con el ajuste activo, anular es «anular con motivo»: sella una versión
voidy exigechangeReason(422reason_required, sin anular nada; solo se comprueba cuando el viaje existe y su mes está abierto). Sin el ajuste,changeReasonse acepta y no se guarda: mándalo siempre. - Anular una línea ya anulada responde 404
trip_not_found. ConIdempotency-Key, un reintento de la misma petición repite el200original.
Errores propios
404 trip_not_found: no existe, es de otra empresa o ya está anulado o descartado.409 trip_in_progress: el viaje está en curso.409 period_closed: mes cerrado del vehículo de la línea (error.periods).422 invalid_input:fields.tripId=requiredoinvalid;fields.changeReason=invalidotoo_long; cualquier otra clave,unexpected_field.422 reason_required: registros inalterables activos y sinchangeReason.423 account_read_only: la cuenta no admite registros (error.reason:account,pending_paymentosuspended).
Petición
Cabeceras
Idempotency-KeystringClave de idempotencia de la escritura (opcional, recomendada). Vale 24 horas por clave API: la misma
Idempotency-Keycon la misma ruta y el mismo cuerpo exacto devuelve la respuesta guardada conIdempotent-Replayed: truesin volver a ejecutar la operación. Con otro cuerpo u otra ruta:409 idempotency_conflict; si la primera aún está en curso:409 idempotency_in_progress. Una respuesta 5xx no se guarda (se puede reintentar). Mal formada:422 invalid_idempotency_key.Patrón:
^[A-Za-z0-9_-]{1,100}$
Cuerpo obligatorio
tripIdinteger | stringobligatorioIdentificador. Entero positivo; también se admite como texto de dígitos (
"412").integer: mínimo
1integer: máximo9007199254740991string: patrón^[1-9][0-9]{0,15}$changeReasonstring | nullMotivo de la anulación (hasta 500 caracteres tras recortar; en blanco = sin motivo). Obligatorio si la empresa tiene registros inalterables (
reason_required); sin el ajuste no se guarda.Hasta 500 caracteres
Ejemplo
curl -sS -X POST "https://app.flotadoc.com/api/movimientos/viajes/delete" \
-H "Authorization: Bearer $FLOTADOC_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-d '{
"tripId": 412,
"changeReason": "Viaje duplicado en el ERP"
}'
Respuesta
200
Viaje anulado.
Cabeceras
X-Request-Idstring (uuid)Id de la petición en el historial de la empresa (para soporte).
Idempotent-Replayedstringtruesi es la respuesta guardada de una petición anterior con la mismaIdempotency-Key.Valores:
true
dataobjectdeletedbooleanSiempre
truetripIdintegerMínimo
1
Ejemplo de respuesta
{
"data": {
"deleted": true,
"tripId": 412
}
}
Además, las respuestas comunes: 401, 403, 404, 409, 422, 423, 429, 503.
Modelos
Objetos que devuelven o reciben las operaciones de esta área. Cada campo enlaza a su modelo.
ViajesTripobject
Un viaje con su coste y su semáforo, calculados en el momento de la lectura.
tripIdintegerMínimo
1tenantIdintegerEmpresa.
Mínimo
1userIdintegerConductor, a cuyo nombre está el viaje.
Mínimo
1userNamestring | nullNombre actual del conductor.
vehicleIdintegerMínimo
1vehiclePlatestring | nullMatrícula actual del vehículo (no se copia al viaje).
statusstringrecorded: registrado a mano a posteriori (web, app o API).in_progress: iniciado en la app y aún sin finalizar.finished: iniciado y finalizado en la app.Valores:
recordedin_progressfinishedtripDatestring (date)Día fiscal del viaje (
YYYY-MM-DD, Europe/Madrid).startedAtstring (date-time) | nullInicio en la app (UTC).
nullen un viajerecorded.endedAtstring (date-time) | nullFin en la app (UTC).
nullen un viajerecordedo en curso.originstring | nullSalida.
nullsolo en un viaje en curso que aún no la tiene.Hasta 200 caracteres
destinationstring | nullDestino.
nullsolo en un viaje en curso.Hasta 200 caracteres
originLatnumber | nullLatitud de la salida (WGS84, 6 decimales).
Mínimo
-90Máximo90originLngnumber | nullLongitud de la salida (WGS84, 6 decimales).
Mínimo
-180Máximo180originAccuracyMnumber | nullPrecisión en metros del punto de salida capturado por el GPS del móvil.
Mínimo
0destinationLatnumber | nullMínimo
-90Máximo90destinationLngnumber | nullMínimo
-180Máximo180destinationAccuracyMnumber | nullMínimo
0distanceKmnumber | nullKm declarados, el dato fiscal.
nullsolo en un viaje en curso.Mayor que
0Máximo99999.99routeKmnumber | nullKm de la ruta estimada, que respaldan los declarados.
Mayor que
0Máximo99999.99routeDurationMininteger | nullDuración de la ruta estimada, en minutos.
Mínimo
0Máximo10080odometerKminteger | nullLectura del cuentakilómetros anotada en el viaje.
Mínimo
0Máximo9999999reasonstring | nullMotivo del viaje (texto libre).
nullsolo en un viaje en curso.Hasta 500 caracteres
reasonCategoryIdinteger | nullMínimo
1reasonCategoryNamestring | nullNombre actual de la categoría, también si se borró del catálogo.
costBasisstringCómo se valora el viaje, copiado del régimen del vehículo al registrarlo:
km_rate(vehículo propio: km × tarifa) ofuel(vehículo de empresa: parte justificada de los gastos de energía del mes).Valores:
km_ratefuelkmRatenumber | nullTarifa (EUR/km) copiada de la empresa al guardar.
nullenfuely en curso.Mínimo
0Máximo10amountnumber | nullROUND(distanceKm × kmRate, 2)en EUR, calculado por la base de datos.nullenfuely en curso.consumptionL100kmnumber | nullConsumo anotado (l/100 km). Solo en
fuel.Mayor que
0Máximo99.99trackKmnumber | nullKm del recorrido GPS grabado, medidos al finalizar.
nullsin recorrido.Mínimo
0trackGapKmnumber | nullKm del recorrido en tramos sin señal.
Mínimo
0hasSignaturebooleanTiene firma del cliente (imagen).
correctedAtstring (date-time) | nullMarca «Corregida»: la última corrección que cambió un dato fiscal (día, vehículo, origen, destino, km, motivo o categoría).
null= nunca.activebooleanfalsesi está anulado o descartado (solo puede llegar así en la sincronización deviajes/list).updatedAtstring (date-time)Último cambio de la fila (UTC, milisegundos). Ordena la sincronización incremental.
apiKeyIdinteger | nullClave API con la que se dio de alta;
nullsi lo registró una persona.Mínimo
1costnumber | nullCoste oficial en EUR: en
km_rate,amount; enfuel, la parte justificada (nullmientras esté pendiente). Calculado al leer.costKindstring | nullallowance: km × tarifa (km_rate).justified: parte justificada (fuel).provisional:fuelsin lectura de fin de mes, vale su coste de consumo (provisionalCost).pending: sin cifra.nullen un viaje en curso.Valores:
justifiedprovisionalallowancependingcostPendingstring | nullPor qué un viaje
fuelya cerrado aún no tiene parte justificada: falta la lectura del cuentakilómetros del mes, o los km de los viajes del mes la superan en 1 km o más.Valores:
missing_odometer_readingodometer_mismatchprovisionalCostnumber | nullSolo con
costKind: provisional.justifiedAmountnumber | nullROUND(monthTicketsAmount × distanceKm ÷ monthShareKm, 2)si el mes cuadra. Solofuel.monthTicketsAmountnumber | nullTotal de los tickets de energía (combustible y recarga) del vehículo en el mes. Solo
fuel.monthOdometerKmnumber | nullKm del mes según el cuentakilómetros. Solo
fuel.monthShareKmnumber | nullKm del reparto: los del cuentakilómetros o, si los viajes del mes los pasan dentro del margen de redondeo (1 km), los de los viajes. Solo
fuel.estimatedLitersnumber | nullROUND(distanceKm × consumptionL100km ÷ 100, 2). Solofuel.consumptionCostnumber | nullLitros estimados × EUR/litro. Solo
fuel.fuelPricePerLiternumber | nullEUR/litro: media de los tickets de combustible del mes o el del último ticket anterior; con el mes cerrado, el congelado en el cierre. Solo
fuel.fuelPriceSourcestring | nullValores:
monthlast_ticketfuelPriceTicketDatestring (date) | nullFecha del ticket del que sale el precio con
last_ticket.alertLevelstring | nullSemáforo:
bad(bloquea el cierre del mes),warn(revisar) uok.nullen un viaje en curso de menos de 12 h.Valores:
okwarnbadalertReasonsstring[]Motivos del semáforo en orden fijo. Rojos:
open_too_long(en curso más de 12 h) yodometer_mismatch(los km del mes superan los del cuentakilómetros). Ámbar:route_deviation(km declarados a más de un 25 % de la ruta estimada),corrected,manual(registrado a mano) ymissing_consumption(vehículo de empresa no eléctrico sin l/100).Valores:
open_too_longodometer_mismatchroute_deviationcorrectedmanualmissing_consumptionattendedByNamestring | nullopcionalQuién atendió y firmó. Solo en
viajes/gety en la respuesta deviajes/save.Hasta 120 caracteres
signedAtstring (date-time) | nullopcionalCuándo se guardó la firma. Solo en
viajes/gety en la respuesta deviajes/save.
ViajesTripDetailobject
El viaje con los datos de la firma del cliente (attendedByName, signedAt).
Incluye todos los campos de ViajesTrip.
attendedByNamestring | nullQuién atendió y firmó. Solo en
viajes/gety en la respuesta deviajes/save.Hasta 120 caracteres
signedAtstring (date-time) | nullCuándo se guardó la firma. Solo en
viajes/gety en la respuesta deviajes/save.
ViajesIntegrationobject | null
Clave API con la que se dio de alta el viaje (también si ya está revocada), o null si lo registró
una persona. name y prefix son null si no se pudieron leer.
apiKeyIdintegerMínimo
1namestring | nullNombre que el owner dio a la clave.
Hasta 60 caracteres
prefixstring | nullPrefijo visible de la clave (nunca la clave entera).
Patrón:
^fd_live_[A-Za-z0-9]{4}$
ViajesTripVersionobject
seqintegerPosición de la entrada en la cadena de huellas de la empresa.
Mínimo
1versioninteger1, 2, 3… dentro del viaje.
Mínimo
1changestringcreatealta o fin ·correctcorrección (también de la firma) ·voidanulación ·technicalpuntos GPS tardíos.Valores:
createcorrectvoidtechnicalauthorobject | nullQuién hizo el cambio;
nullsolo en una versióntechnical.userIdintegerMínimo
1namestring | nullnullsi la persona no se ve desde la empresa (equipo de FlotaDoc).
recordedAtstring (date-time)Hora del sellado (UTC).
reasonstring | nullMotivo del cambio (
changeReason).nullen un alta y en una versióntechnical.Hasta 500 caracteres
snapshotViajesTripSnapshot | nullInstantánea fiscal después del cambio.
nullen una versióntechnicaloredacted.filesViajesSealFile[]Huellas de los ficheros de la versión (sin claves ni nombres de S3).
changedstring[]Claves de la instantánea que cambiaron respecto a la versión anterior (
[]en la primera).entryHashstringHuella SHA-256 de la entrada en la cadena.
Patrón:
^[0-9a-f]{64}$redactedbooleantruesi el contenido falta o no se entiende (alteración:verifyla da por rota).
ViajesReasonCategoryobject
reasonCategoryIdintegerMínimo
1namestringDe 1 a 60 caracteres
isDefaultbooleanUna de las seis por defecto (aunque se haya renombrado).
updatedAtstring (date-time)
ViajesTripSnapshotobject
Lo que la asesoría y Hacienda miran de la línea del libro en esa versión.
statusstringrecorded: registrado a mano a posteriori (web, app o API).in_progress: iniciado en la app y aún sin finalizar.finished: iniciado y finalizado en la app.Valores:
recordedin_progressfinishedtripDatestring (date)userIdintegerConductor.
vehicleIdintegerstartedAtstring | nullUTC con microsegundos (
YYYY-MM-DDTHH:MM:SS.ffffffZ).endedAtstring | nullUTC con microsegundos.
originstring | nulloriginLatnumber | nulloriginLngnumber | nulldestinationstring | nulldestinationLatnumber | nulldestinationLngnumber | nulldistanceKmnumber | nullodometerKminteger | nullreasonstring | nullMotivo del viaje.
reasonCategorystring | nullNombre de la categoría en ese momento.
costBasisstringCómo se valora el viaje, copiado del régimen del vehículo al registrarlo:
km_rate(vehículo propio: km × tarifa) ofuel(vehículo de empresa: parte justificada de los gastos de energía del mes).Valores:
km_ratefuelkmRatenumber | nullamountnumber | nullattendedByNamestring | nullsignedAtstring | nullUTC con microsegundos.
signatureSha256string | nullHuella de la imagen de la firma.
Patrón:
^[0-9a-f]{64}$
ViajesSealFileobject
kindstringsignatureimagen de la firma del cliente (como mucho una) ·trackrecorrido GPS.Valores:
signaturetracksha256stringPatrón:
^[0-9a-f]{64}$bytesintegeropcionalTamaño en bytes, si se conoce.
Mínimo
0
¿Quieres conectar tu sistema?
Cuéntanos qué quieres integrar y lo vemos en una llamada: qué datos necesitas, con qué permisos y cada cuánto.
Si tu empresa ya usa FlotaDoc, el titular puede pedir el acceso desde la web, en Mi cuenta › Integraciones.