{
  "openapi": "3.1.0",
  "info": {
    "title": "API de la plataforma GPS de Tracker International (solo lectura)",
    "version": "1.0.0",
    "summary": "Endpoints de lectura verificados de la API de la plataforma GPS de Tracker International.",
    "description": "Referencia pública de la API de lectura de la plataforma GPS de Tracker International. Solo incluye los endpoints de lectura que se verificaron; no incluye endpoints de escritura. Cada operación declara su estado (`x-estado`: verificado o parcial), la fecha y cómo se verificó (`x-verificado`, `x-verificacion`).\n\n**Autenticación**: envía el `user_api_hash` en la cabecera `user-api-hash`. También se admite el parámetro `user_api_hash`, pero evítalo: las URL quedan en registros de acceso. `Authorization: Bearer` no funciona.\n\n**Zonas horarias**: las fechas de entrada se interpretan en la zona horaria de la cuenta. Las de salida vienen mezcladas: campos formateados con el formato y la zona de la cuenta, y campos crudos (`device_time`, `created_at`, `updated_at`…) en UTC.\n\n**Errores**: 401 `{status, message}`; 403, 404, 422 y 500 `{statusCode, message, status, errors}`. Algunos errores de validación llegan con HTTP 200 y `{status: 0, errors}`: comprueba siempre `status`.\n\n**Límites**: no hay un límite global en el código. Solo `login` (60/min), `point_in_geofences` (30/min) y `devices_in_geofences` (1800/min). Los valores de producción no están confirmados.\n\n**Seguridad**: el hash no es de solo lectura; concede los mismos permisos que la contraseña del usuario. Crea un usuario dedicado con permisos solo de \"ver\" para tus integraciones.",
    "contact": {
      "name": "Tracker International",
      "url": "https://trackerintl.com/contacto"
    },
    "license": {
      "name": "Uso interno (propietario)",
      "identifier": "LicenseRef-Proprietary"
    },
    "x-generado": {
      "fecha": "2026-10-05",
      "huella_fuente": "e08bf8e75105d1d4",
      "portal": "https://trackerintl.com/devs"
    }
  },
  "servers": [
    {
      "url": "https://plataforma.trackerintl.com",
      "description": "Dominio base de la plataforma. Si tu cuenta pertenece a un revendedor marca blanca, usa el dominio que te indique quien administra tu cuenta."
    }
  ],
  "security": [
    {
      "UserApiHashHeader": []
    },
    {
      "UserApiHashQuery": []
    }
  ],
  "tags": [
    {
      "name": "Autenticación",
      "description": "Obtención de la credencial user_api_hash."
    },
    {
      "name": "Cuenta",
      "description": "Datos del usuario de la API, conductores y comandos enviados."
    },
    {
      "name": "Vehículos",
      "description": "Listado de vehículos y última posición."
    },
    {
      "name": "Historial",
      "description": "Recorridos por tramos y posiciones GPS crudas."
    },
    {
      "name": "Eventos y alertas",
      "description": "Reglas de alerta y eventos disparados."
    },
    {
      "name": "Geocercas y rutas",
      "description": "Geocercas, rutas planificadas y consultas punto-en-geocerca."
    },
    {
      "name": "Reportes",
      "description": "Catálogo de tipos de reporte y plantillas guardadas (no genera reportes)."
    }
  ],
  "paths": {
    "/api/login": {
      "post": {
        "operationId": "login",
        "tags": [
          "Autenticación"
        ],
        "summary": "Obtener el hash de API (user_api_hash)",
        "description": "Canjea correo y contraseña por el `user_api_hash`, la credencial que se envía en el resto de las peticiones. Acepta cuerpo JSON o formulario. Si el usuario aún no tiene hash, la plataforma lo genera en ese momento.\n\nNotas:\n- Según el código, el hash no caduca por tiempo y cambia cuando el usuario cambia su contraseña. No se midió en producción.\n- Límite de 60 peticiones por minuto (valor por defecto del código; el valor de producción no está confirmado).\n- El hash concede los mismos permisos que la contraseña del usuario. No existen claves de solo lectura ni por alcance.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  }
                },
                "required": [
                  "email",
                  "password"
                ],
                "additionalProperties": true
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  }
                },
                "required": [
                  "email",
                  "password"
                ],
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResponse"
                },
                "example": {
                  "status": 1,
                  "user_api_hash": "TU_API_HASH",
                  "permissions": {
                    "devices": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "alerts": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "events": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "geofences": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "routes": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "reports": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "history": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "send_command": {
                      "view": false,
                      "edit": false,
                      "remove": false
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "422": {
            "description": "Faltan email/password. Forma {status:0,errors:{campo:[..]}} (sin statusCode).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorValidationHttp200"
                },
                "example": {
                  "status": 0,
                  "errors": {
                    "email": [
                      "The Email field is required."
                    ],
                    "password": [
                      "The Password field is required."
                    ]
                  }
                }
              }
            }
          },
          "429": {
            "description": "Límite de peticiones superado (inferido del comportamiento estándar; no medido)."
          }
        },
        "x-rate-limit": {
          "limit": 60,
          "window": "1 min",
          "headers": [
            "X-RateLimit-Limit",
            "X-RateLimit-Remaining"
          ]
        },
        "x-estado": "parcial",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y código idéntico al verificado. Los errores 401 y 422 se midieron en un entorno de pruebas; la respuesta 200 se lee del código porque no se hizo un inicio de sesión real."
      }
    },
    "/api/get_user_data": {
      "get": {
        "operationId": "getUserData",
        "tags": [
          "Cuenta"
        ],
        "summary": "Datos y permisos del usuario de la API",
        "description": "Devuelve el correo, el plan, el vencimiento de la suscripción, los días restantes, el límite de vehículos y la matriz de permisos del usuario. Úsalo para comprobar que la credencial funciona.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserData"
                },
                "example": {
                  "email": "demo@example.invalid",
                  "expiration_date": "31-12-2030 23:59:59",
                  "days_left": 1547,
                  "plan": "Plan de demostracion (ficticio)",
                  "devices_limit": 10,
                  "group_id": 2,
                  "role_id": 2,
                  "permissions": {
                    "devices": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "alerts": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "events": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "geofences": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "routes": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "reports": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "history": {
                      "view": true,
                      "edit": false,
                      "remove": false
                    },
                    "send_command": {
                      "view": false,
                      "edit": false,
                      "remove": false
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_devices": {
      "get": {
        "operationId": "getDevices",
        "tags": [
          "Vehículos"
        ],
        "summary": "Listar vehículos agrupados con su última posición",
        "description": "Devuelve un arreglo de grupos `{id, title, items[]}`; el grupo `0` reúne los vehículos sin grupo. Cada elemento trae la última posición válida, el estado calculado, los sensores y los servicios. Con `page` o `limit` pagina por vehículo antes de agrupar, así que un grupo puede repartirse entre páginas; si solo envías `page`, `limit` vale 100. Sin ninguno de los dos recorre todos los vehículos. Si el usuario no tiene permiso para ver vehículos responde `[]` con HTTP 200.\n\nNotas:\n- Medido en un entorno de pruebas: la respuesta falla con HTTP 500 si algún vehículo de la cuenta tiene el icono sin asignar. No se comprobó cuántos vehículos de producción están en ese caso.\n- Los filtros de texto (`s`) buscan en nombre, IMEI, placa y otros campos del vehículo.",
        "parameters": [
          {
            "name": "s",
            "in": "query",
            "required": false,
            "description": "Búsqueda de texto; varios términos separados por \";\" (OR). Medido con valor simple.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Vehículos por página. Sin tope en el código (se recomienda ≤ 200).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Página (pasar page o limit activa la paginación).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "device_id",
            "in": "query",
            "required": false,
            "description": "Filtro por ID.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Equivale a device_id (también filtra).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "imei",
            "in": "query",
            "required": false,
            "description": "IMEI exacto.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plate_number",
            "in": "query",
            "required": false,
            "description": "Placa exacta.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group_id",
            "in": "query",
            "required": false,
            "description": "0 = sin grupo.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Estado, puede repetirse como arreglo.",
            "schema": {
              "type": "string",
              "enum": [
                "expired",
                "offline",
                "online",
                "inactive",
                "move",
                "stop",
                "park",
                "idle",
                "engine_on",
                "engine_off",
                "blocked",
                "not_connected",
                "never_connected"
              ]
            }
          },
          {
            "name": "online",
            "in": "query",
            "required": false,
            "description": "Minutos: conectados en los últimos N minutos.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offline",
            "in": "query",
            "required": false,
            "description": "Minutos: sin conexión hace más de N minutos.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DeviceGroup"
                  }
                },
                "example": [
                  {
                    "id": 0,
                    "title": "Sin grupo",
                    "items": [
                      {
                        "id": 9001,
                        "alarm": 0,
                        "name": "Camioneta de prueba 01",
                        "online": "online",
                        "time": "05-10-2026 16:11:06",
                        "no_position_update": false,
                        "last_position_time": "05-10-2026 16:10:58",
                        "timestamp": 1791231058,
                        "acktimestamp": 1791231066,
                        "lat": -17.7733,
                        "lng": -63.192099999999996,
                        "course": 208,
                        "speed": 42,
                        "altitude": 415,
                        "icon_type": "rotating",
                        "icon_color": "green",
                        "icon_colors": {
                          "moving": "green",
                          "stopped": "yellow",
                          "offline": "red",
                          "engine": "yellow",
                          "blocked": "black"
                        },
                        "icon": {
                          "id": 79,
                          "user_id": null,
                          "type": "rotating",
                          "order": null,
                          "width": 25,
                          "height": 51,
                          "path": "images/device_icons/ejemplo_online.png",
                          "by_status": 1
                        },
                        "power": "-",
                        "address": "-",
                        "protocol": "gt06",
                        "driver": "-",
                        "driver_data": {
                          "id": null,
                          "user_id": null,
                          "device_id": null,
                          "name": null,
                          "rfid": null,
                          "phone": null,
                          "email": null,
                          "description": null,
                          "created_at": null,
                          "updated_at": null
                        },
                        "sensors": [
                          {
                            "id": 70001,
                            "type": "battery",
                            "name": "Bateria",
                            "show_in_popup": 1,
                            "value": "87 %",
                            "val": 87,
                            "scale_value": 87,
                            "tag_name": "batterylevel"
                          },
                          {
                            "id": 70002,
                            "type": "ignition",
                            "name": "Ignicion",
                            "show_in_popup": 1,
                            "value": "Encendido",
                            "val": true,
                            "scale_value": 1,
                            "tag_name": "ignition"
                          }
                        ],
                        "services": [
                          {
                            "id": 80001,
                            "name": "Cambio de aceite",
                            "value": "Days Left (56d.)",
                            "expiring": false,
                            "expiration_by": "days"
                          }
                        ],
                        "tail": [
                          {
                            "lat": "-17.7811",
                            "lng": "-63.1843"
                          },
                          {
                            "lat": "-17.7820",
                            "lng": "-63.1835"
                          }
                        ],
                        "distance_unit_hour": "kph",
                        "unit_of_distance": "Km",
                        "unit_of_altitude": "m",
                        "unit_of_capacity": "L",
                        "stop_duration": "-",
                        "stop_duration_sec": 0,
                        "moved_timestamp": 1791231000,
                        "engine_status": true,
                        "detect_engine": "gps",
                        "engine_hours": "gps",
                        "total_distance": 12176.23,
                        "inaccuracy": null,
                        "sim_expiration_date": "-",
                        "device_data": {
                          "id": 9001,
                          "user_id": 1,
                          "traccar_device_id": 9001,
                          "icon_id": 79,
                          "active": 1,
                          "enable": 1,
                          "deleted": 0,
                          "name": "Camioneta de prueba 01",
                          "imei": "999000000000001",
                          "sim_number": "5550000001",
                          "plate_number": "TEST-001",
                          "vin": "",
                          "tail_length": 5,
                          "min_moving_speed": 6,
                          "expiration_date": null,
                          "created_at": "2025-12-03 19:20:07",
                          "updated_at": "2026-10-05 20:10:58",
                          "pivot": {
                            "user_id": 1,
                            "device_id": 9001,
                            "group_id": 0,
                            "active": 1,
                            "current_driver_id": null,
                            "timezone_id": null
                          },
                          "group_id": 0,
                          "lastValidLatitude": -17.7733,
                          "lastValidLongitude": -63.192099999999996,
                          "time": "05-10-2026 16:11:06",
                          "course": 208,
                          "speed": 42
                        }
                      }
                    ]
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción. Los archivos del flujo coinciden con los verificados, salvo dos campos que producción añade (`no_position_update` y `last_position_time`). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_devices_latest": {
      "get": {
        "operationId": "getDevicesLatest",
        "tags": [
          "Vehículos"
        ],
        "summary": "Vehículos con posición actualizada desde un instante (delta) + eventos recientes",
        "description": "Modo delta: devuelve solo los vehículos cuya posición se actualizó desde el instante `time` (segundos Unix, UTC) y, además, `events` con los eventos recientes (hasta 5 minutos atrás). `time` vacío o `0` se interpreta como \"hace 5 segundos\"; para obtener todos los vehículos envía `time=1`. Guarda el `time` de la respuesta y úsalo en la consulta siguiente. `sensors`, `services` y `tail` de cada vehículo llegan como cadenas JSON que debes decodificar.\n\nNotas:\n- Comparte con `get_devices` el riesgo de HTTP 500 si algún vehículo tiene el icono sin asignar.",
        "parameters": [
          {
            "name": "time",
            "in": "query",
            "required": false,
            "description": "Segundos Unix UTC. Por defecto ahora−5 s. Usa 1 para todo.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "device_id",
            "in": "query",
            "required": false,
            "description": "Un vehículo.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Un vehículo.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "imei",
            "in": "query",
            "required": false,
            "description": "IMEI.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Vehículos por página (por defecto 100 si se envía page).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Página.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DevicesLatestResponse"
                },
                "example": {
                  "items": [
                    {
                      "id": 9001,
                      "alarm": 0,
                      "name": "Camioneta de prueba 01",
                      "online": "online",
                      "time": "05-10-2026 16:11:06",
                      "no_position_update": false,
                      "last_position_time": "05-10-2026 16:10:58",
                      "timestamp": 1791231058,
                      "acktimestamp": 1791231066,
                      "lat": -17.7733,
                      "lng": -63.192099999999996,
                      "course": 208,
                      "speed": 42,
                      "altitude": 415,
                      "icon_type": "rotating",
                      "icon_color": "green",
                      "icon_colors": {
                        "moving": "green",
                        "stopped": "yellow",
                        "offline": "red",
                        "engine": "yellow",
                        "blocked": "black"
                      },
                      "icon": {
                        "id": 79,
                        "user_id": null,
                        "type": "rotating",
                        "order": null,
                        "width": 25,
                        "height": 51,
                        "path": "images/device_icons/ejemplo_online.png",
                        "by_status": 1
                      },
                      "power": "-",
                      "address": "-",
                      "protocol": "gt06",
                      "driver": "-",
                      "driver_data": {
                        "id": null,
                        "user_id": null,
                        "device_id": null,
                        "name": null,
                        "rfid": null,
                        "phone": null,
                        "email": null,
                        "description": null,
                        "created_at": null,
                        "updated_at": null
                      },
                      "sensors": "[{\"id\":70001,\"type\":\"battery\",\"name\":\"Bateria\",\"show_in_popup\":1,\"value\":\"87 %\",\"val\":87,\"scale_value\":87,\"tag_name\":\"batterylevel\"},{\"id\":70002,\"type\":\"ignition\",\"name\":\"Ignicion\",\"show_in_popup\":1,\"value\":\"Encendido\",\"val\":true,\"scale_value\":1,\"tag_name\":\"ignition\"}]",
                      "services": "[{\"id\":80001,\"name\":\"Cambio de aceite\",\"value\":\"Days Left (56d.)\",\"expiring\":false,\"expiration_by\":\"days\"}]",
                      "tail": "[{\"lat\":\"-17.7811\",\"lng\":\"-63.1843\"},{\"lat\":\"-17.7820\",\"lng\":\"-63.1835\"}]",
                      "distance_unit_hour": "kph",
                      "unit_of_distance": "Km",
                      "unit_of_altitude": "m",
                      "unit_of_capacity": "L",
                      "stop_duration": "-",
                      "stop_duration_sec": 0,
                      "moved_timestamp": 1791231000,
                      "engine_status": true,
                      "detect_engine": "gps",
                      "engine_hours": "gps",
                      "total_distance": 12176.23,
                      "inaccuracy": null,
                      "sim_expiration_date": "-",
                      "device_data": {
                        "id": 9001,
                        "user_id": 1,
                        "traccar_device_id": 9001,
                        "icon_id": 79,
                        "active": 1,
                        "enable": 1,
                        "deleted": 0,
                        "name": "Camioneta de prueba 01",
                        "imei": "999000000000001",
                        "sim_number": "5550000001",
                        "plate_number": "TEST-001",
                        "vin": "",
                        "tail_length": 5,
                        "min_moving_speed": 6,
                        "expiration_date": null,
                        "created_at": "2025-12-03 19:20:07",
                        "updated_at": "2026-10-05 20:10:58",
                        "pivot": {
                          "user_id": 1,
                          "device_id": 9001,
                          "group_id": 0,
                          "active": 1,
                          "current_driver_id": null,
                          "timezone_id": null
                        },
                        "group_id": 0,
                        "lastValidLatitude": -17.7733,
                        "lastValidLongitude": -63.192099999999996,
                        "time": "05-10-2026 16:11:06",
                        "course": 208,
                        "speed": 42
                      }
                    }
                  ],
                  "events": [],
                  "time": 1791231068,
                  "version": "3.7.13"
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción. Mismas dos diferencias aditivas que `get_devices`. La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_history": {
      "get": {
        "operationId": "getHistory",
        "tags": [
          "Historial"
        ],
        "summary": "Recorrido de un vehículo por tramos de conducción/parada",
        "description": "Reconstruye el recorrido de un vehículo en tramos de conducción y de parada. Identifica el vehículo con `device_id` o con `imei`. Las fechas y horas se interpretan en la zona horaria de la cuenta, no en UTC. Rango máximo de 31 días (valor por defecto del código; el de producción no está confirmado). Requiere permiso de historial, que el vehículo sea del usuario y que no esté vencido.\n\nNotas:\n- Dentro de cada posición, `raw_time` y `time` están en la zona de la cuenta, mientras que `device_time` y `server_time` vienen crudos en UTC.",
        "parameters": [
          {
            "name": "device_id",
            "in": "query",
            "required": false,
            "description": "Obligatorio si no se envía imei.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "imei",
            "in": "query",
            "required": false,
            "description": "Alternativa a device_id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from_date",
            "in": "query",
            "required": true,
            "description": "Fecha inicial YYYY-MM-DD. Zona horaria: la de la cuenta del usuario de la API, no UTC. Formato de visualización: el configurado en la cuenta (en las mediciones fue dd-mm-YYYY HH:mm:ss).",
            "schema": {
              "type": "string",
              "format": "date",
              "examples": [
                "2026-10-01"
              ]
            }
          },
          {
            "name": "from_time",
            "in": "query",
            "required": true,
            "description": "Hora inicial HH:MM o HH:MM:SS (validación: regex).",
            "schema": {
              "type": "string",
              "pattern": "^\\d{2}:\\d{2}(:\\d{2})?$",
              "examples": [
                "00:00"
              ]
            }
          },
          {
            "name": "to_date",
            "in": "query",
            "required": true,
            "description": "Fecha final YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date",
              "examples": [
                "2026-10-02"
              ]
            }
          },
          {
            "name": "to_time",
            "in": "query",
            "required": true,
            "description": "Hora final HH:MM o HH:MM:SS.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{2}:\\d{2}(:\\d{2})?$",
              "examples": [
                "23:59"
              ]
            }
          },
          {
            "name": "stops",
            "in": "query",
            "required": false,
            "description": "Segundos mínimos para considerar una parada (por defecto 180).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoryResponse"
                },
                "example": {
                  "items": [
                    {
                      "status": 3,
                      "time": null,
                      "show": "01-10-2026 08:00:00",
                      "raw_time": "2026-10-01 08:00:00",
                      "distance": 0,
                      "driver": null,
                      "items": [
                        {
                          "id": 500,
                          "device_id": 9001,
                          "item_id": "i500",
                          "time": "01-10-2026 08:00:00",
                          "raw_time": "2026-10-01 08:00:00",
                          "altitude": 400,
                          "course": 90,
                          "speed": 27,
                          "latitude": -17.78,
                          "longitude": -63.18,
                          "lat": -17.78,
                          "lng": -63.18,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 12:00:00",
                          "server_time": "2026-10-01 12:00:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 27
                            },
                            {
                              "id": "altitude",
                              "value": 400
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "status": 1,
                      "index": 1,
                      "time": "40min 0s",
                      "show": "01-10-2026 08:00:00",
                      "left": "01-10-2026 08:40:00",
                      "raw_time": "2026-10-01 08:00:00",
                      "distance": 2.91,
                      "time_seconds": 2400,
                      "engine_work": 2280,
                      "engine_idle": 0,
                      "engine_hours": 2280,
                      "fuel_consumption": null,
                      "top_speed": 27,
                      "average_speed": 27,
                      "driver": null,
                      "items": [
                        {
                          "id": 500,
                          "device_id": 9001,
                          "item_id": "i500",
                          "time": "01-10-2026 08:00:00",
                          "raw_time": "2026-10-01 08:00:00",
                          "altitude": 400,
                          "course": 90,
                          "speed": 27,
                          "latitude": -17.78,
                          "longitude": -63.18,
                          "lat": -17.78,
                          "lng": -63.18,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 12:00:00",
                          "server_time": "2026-10-01 12:00:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 27
                            },
                            {
                              "id": "altitude",
                              "value": 400
                            }
                          ]
                        },
                        {
                          "id": 501,
                          "device_id": 9001,
                          "item_id": "i501",
                          "time": "01-10-2026 08:02:00",
                          "raw_time": "2026-10-01 08:02:00",
                          "altitude": 401,
                          "course": 90,
                          "speed": 27,
                          "latitude": -17.779,
                          "longitude": -63.179,
                          "lat": -17.779,
                          "lng": -63.179,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 12:02:00",
                          "server_time": "2026-10-01 12:02:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 27
                            },
                            {
                              "id": "altitude",
                              "value": 401
                            }
                          ]
                        },
                        {
                          "id": 502,
                          "device_id": 9001,
                          "item_id": "i502",
                          "time": "01-10-2026 08:04:00",
                          "raw_time": "2026-10-01 08:04:00",
                          "altitude": 402,
                          "course": 90,
                          "speed": 27,
                          "latitude": -17.778000000000002,
                          "longitude": -63.178,
                          "lat": -17.778000000000002,
                          "lng": -63.178,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 12:04:00",
                          "server_time": "2026-10-01 12:04:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 27
                            },
                            {
                              "id": "altitude",
                              "value": 402
                            }
                          ]
                        },
                        {
                          "id": 503,
                          "device_id": 9001,
                          "item_id": "i503",
                          "time": "01-10-2026 08:06:00",
                          "raw_time": "2026-10-01 08:06:00",
                          "altitude": 403,
                          "course": 90,
                          "speed": 27,
                          "latitude": -17.777,
                          "longitude": -63.177,
                          "lat": -17.777,
                          "lng": -63.177,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 12:06:00",
                          "server_time": "2026-10-01 12:06:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 27
                            },
                            {
                              "id": "altitude",
                              "value": 403
                            }
                          ]
                        },
                        {
                          "id": 504,
                          "device_id": 9001,
                          "item_id": "i504",
                          "time": "01-10-2026 08:08:00",
                          "raw_time": "2026-10-01 08:08:00",
                          "altitude": 404,
                          "course": 90,
                          "speed": 27,
                          "latitude": -17.776,
                          "longitude": -63.176,
                          "lat": -17.776,
                          "lng": -63.176,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 12:08:00",
                          "server_time": "2026-10-01 12:08:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 27
                            },
                            {
                              "id": "altitude",
                              "value": 404
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "status": 2,
                      "index": 1,
                      "time": "30min 0s",
                      "show": "01-10-2026 08:40:00",
                      "left": "01-10-2026 09:10:00",
                      "raw_time": "2026-10-01 08:40:00",
                      "distance": 0,
                      "time_seconds": 1800,
                      "engine_work": 0,
                      "engine_idle": 0,
                      "engine_hours": 0,
                      "fuel_consumption": null,
                      "top_speed": 0,
                      "average_speed": 0,
                      "driver": null,
                      "items": [
                        {
                          "id": 520,
                          "device_id": 9001,
                          "item_id": "i520",
                          "time": "01-10-2026 08:40:00",
                          "raw_time": "2026-10-01 08:40:00",
                          "altitude": 420,
                          "course": 90,
                          "speed": 0,
                          "latitude": -17.76,
                          "longitude": -63.16,
                          "lat": -17.76,
                          "lng": -63.16,
                          "distance": 0,
                          "other": "<info><ignition>0</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 12:40:00",
                          "server_time": "2026-10-01 12:40:00",
                          "other_arr": [
                            "ignition: 0"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 0
                            },
                            {
                              "id": "altitude",
                              "value": 420
                            }
                          ]
                        },
                        {
                          "id": 521,
                          "device_id": 9001,
                          "item_id": "i521",
                          "time": "01-10-2026 08:42:00",
                          "raw_time": "2026-10-01 08:42:00",
                          "altitude": 421,
                          "course": 90,
                          "speed": 0,
                          "latitude": -17.759,
                          "longitude": -63.159,
                          "lat": -17.759,
                          "lng": -63.159,
                          "distance": 0,
                          "other": "<info><ignition>0</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 12:42:00",
                          "server_time": "2026-10-01 12:42:00",
                          "other_arr": [
                            "ignition: 0"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 0
                            },
                            {
                              "id": "altitude",
                              "value": 421
                            }
                          ]
                        },
                        {
                          "id": 522,
                          "device_id": 9001,
                          "item_id": "i522",
                          "time": "01-10-2026 08:44:00",
                          "raw_time": "2026-10-01 08:44:00",
                          "altitude": 422,
                          "course": 90,
                          "speed": 0,
                          "latitude": -17.758000000000003,
                          "longitude": -63.158,
                          "lat": -17.758000000000003,
                          "lng": -63.158,
                          "distance": 0,
                          "other": "<info><ignition>0</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 12:44:00",
                          "server_time": "2026-10-01 12:44:00",
                          "other_arr": [
                            "ignition: 0"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 0
                            },
                            {
                              "id": "altitude",
                              "value": 422
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "status": 1,
                      "index": 2,
                      "time": "48min 0s",
                      "show": "01-10-2026 09:10:00",
                      "left": "01-10-2026 09:58:00",
                      "raw_time": "2026-10-01 09:10:00",
                      "distance": 6.29,
                      "time_seconds": 2880,
                      "engine_work": 2880,
                      "engine_idle": 0,
                      "engine_hours": 2880,
                      "fuel_consumption": null,
                      "top_speed": 31,
                      "average_speed": 29,
                      "driver": null,
                      "items": [
                        {
                          "id": 535,
                          "device_id": 9001,
                          "item_id": "i535",
                          "time": "01-10-2026 09:10:00",
                          "raw_time": "2026-10-01 09:10:00",
                          "altitude": 435,
                          "course": 90,
                          "speed": 31,
                          "latitude": -17.745,
                          "longitude": -63.145,
                          "lat": -17.745,
                          "lng": -63.145,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 13:10:00",
                          "server_time": "2026-10-01 13:10:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 31
                            },
                            {
                              "id": "altitude",
                              "value": 435
                            }
                          ]
                        },
                        {
                          "id": 536,
                          "device_id": 9001,
                          "item_id": "i536",
                          "time": "01-10-2026 09:12:00",
                          "raw_time": "2026-10-01 09:12:00",
                          "altitude": 436,
                          "course": 90,
                          "speed": 31,
                          "latitude": -17.744,
                          "longitude": -63.144,
                          "lat": -17.744,
                          "lng": -63.144,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 13:12:00",
                          "server_time": "2026-10-01 13:12:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 31
                            },
                            {
                              "id": "altitude",
                              "value": 436
                            }
                          ]
                        },
                        {
                          "id": 537,
                          "device_id": 9001,
                          "item_id": "i537",
                          "time": "01-10-2026 09:14:00",
                          "raw_time": "2026-10-01 09:14:00",
                          "altitude": 437,
                          "course": 90,
                          "speed": 31,
                          "latitude": -17.743000000000002,
                          "longitude": -63.143,
                          "lat": -17.743000000000002,
                          "lng": -63.143,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 13:14:00",
                          "server_time": "2026-10-01 13:14:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 31
                            },
                            {
                              "id": "altitude",
                              "value": 437
                            }
                          ]
                        },
                        {
                          "id": 538,
                          "device_id": 9001,
                          "item_id": "i538",
                          "time": "01-10-2026 09:16:00",
                          "raw_time": "2026-10-01 09:16:00",
                          "altitude": 438,
                          "course": 90,
                          "speed": 31,
                          "latitude": -17.742,
                          "longitude": -63.142,
                          "lat": -17.742,
                          "lng": -63.142,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 13:16:00",
                          "server_time": "2026-10-01 13:16:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 31
                            },
                            {
                              "id": "altitude",
                              "value": 438
                            }
                          ]
                        }
                      ]
                    },
                    {
                      "status": 4,
                      "time": null,
                      "show": "01-10-2026 09:58:00",
                      "raw_time": "2026-10-01 09:58:00",
                      "distance": 0,
                      "driver": null,
                      "items": [
                        {
                          "id": 538,
                          "device_id": 9001,
                          "item_id": "i538",
                          "time": "01-10-2026 09:16:00",
                          "raw_time": "2026-10-01 09:16:00",
                          "altitude": 438,
                          "course": 90,
                          "speed": 31,
                          "latitude": -17.742,
                          "longitude": -63.142,
                          "lat": -17.742,
                          "lng": -63.142,
                          "distance": 0.12,
                          "other": "<info><ignition>1</ignition></info>",
                          "color": "#000000",
                          "valid": 1,
                          "device_time": "2026-10-01 13:16:00",
                          "server_time": "2026-10-01 13:16:00",
                          "other_arr": [
                            "ignition: 1"
                          ],
                          "sensors_data": [
                            {
                              "id": "speed",
                              "value": 31
                            },
                            {
                              "id": "altitude",
                              "value": 438
                            }
                          ]
                        }
                      ]
                    }
                  ],
                  "device": {
                    "id": 9001,
                    "name": "Camioneta de prueba 01",
                    "imei": "999000000000001",
                    "plate_number": "TEST-001",
                    "sensors": [],
                    "traccar": {}
                  },
                  "distance_sum": "9.2 Km",
                  "top_speed": "31 kph",
                  "move_duration": "1h 28min 0s",
                  "stop_duration": "30min 0s",
                  "engine_hours": "1h 28min 0s",
                  "engine_idle": "0s",
                  "engine_work": "1h 28min 0s",
                  "fuel_consumption": null,
                  "sensors": [
                    {
                      "id": "speed",
                      "name": "Speed",
                      "sufix": "kph"
                    },
                    {
                      "id": "altitude",
                      "name": "Altitude",
                      "sufix": "m"
                    }
                  ],
                  "fuel_consumption_arr": [],
                  "item_class": [
                    {
                      "id": 1,
                      "value": "drive",
                      "title": "Drive"
                    },
                    {
                      "id": 2,
                      "value": "stop",
                      "title": "Stop"
                    },
                    {
                      "id": 3,
                      "value": "start",
                      "title": "Start"
                    },
                    {
                      "id": 4,
                      "value": "end",
                      "title": "End"
                    },
                    {
                      "id": 5,
                      "value": "event",
                      "title": "Event"
                    }
                  ],
                  "images": [
                    {
                      "id": 1,
                      "value": "https://example.invalid/assets/images/route_drive.png",
                      "title": "https://example.invalid/assets/images/route_drive.png"
                    }
                  ],
                  "status": 1
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "404": {
            "description": "Dispositivo inexistente: message \"\\\"Device\\\" was not found.\".",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "422": {
            "description": "Faltan parámetros, formato de hora inválido, rango > 31 días o vehículo vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_history_messages": {
      "get": {
        "operationId": "getHistoryMessages",
        "tags": [
          "Historial"
        ],
        "summary": "Posiciones GPS crudas paginadas",
        "description": "Lista las posiciones almacenadas de un vehículo en el rango dado, paginadas. `limit` solo admite 50, 100, 200, 300, 400, 500 o 1000; cualquier otro valor se sustituye por 50 sin avisar. `sorting=true` ordena de la más reciente a la más antigua. A diferencia de `get_history`, no aplica el límite de 31 días y exige `device_id` (no acepta `imei`).\n\nNotas:\n- Aunque este endpoint no limita el rango, conviene consultar por tramos de hasta 31 días, igual que `get_history`.",
        "parameters": [
          {
            "name": "device_id",
            "in": "query",
            "required": true,
            "description": "ID del vehículo (campo id de get_devices).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "from_date",
            "in": "query",
            "required": true,
            "description": "Fecha inicial YYYY-MM-DD. Zona horaria: la de la cuenta del usuario de la API, no UTC. Formato de visualización: el configurado en la cuenta (en las mediciones fue dd-mm-YYYY HH:mm:ss).",
            "schema": {
              "type": "string",
              "format": "date",
              "examples": [
                "2026-10-01"
              ]
            }
          },
          {
            "name": "from_time",
            "in": "query",
            "required": true,
            "description": "Hora inicial HH:MM o HH:MM:SS (validación: regex).",
            "schema": {
              "type": "string",
              "pattern": "^\\d{2}:\\d{2}(:\\d{2})?$",
              "examples": [
                "00:00"
              ]
            }
          },
          {
            "name": "to_date",
            "in": "query",
            "required": true,
            "description": "Fecha final YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date",
              "examples": [
                "2026-10-02"
              ]
            }
          },
          {
            "name": "to_time",
            "in": "query",
            "required": true,
            "description": "Hora final HH:MM o HH:MM:SS.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{2}:\\d{2}(:\\d{2})?$",
              "examples": [
                "23:59"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Tamaño de página (valor distinto -> 50).",
            "schema": {
              "type": "integer",
              "enum": [
                50,
                100,
                200,
                300,
                400,
                500,
                1000
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Número de página.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "sorting",
            "in": "query",
            "required": false,
            "description": "true = descendente.",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PositionMessagesResponse"
                },
                "example": {
                  "messages": {
                    "current_page": 1,
                    "data": [
                      {
                        "id": 1000,
                        "altitude": 400,
                        "course": 90,
                        "latitude": -17.78,
                        "longitude": -63.18,
                        "other": "<info><ignition>1</ignition><totaldistance>1000</totaldistance></info>",
                        "speed": "27.00",
                        "time": "01-10-2026 08:00:00",
                        "device_time": "2026-10-01 12:00:00",
                        "server_time": "01-10-2026 08:00:00",
                        "sensors_values": null,
                        "valid": 1,
                        "distance": 120,
                        "protocol": "gt06",
                        "device_id": 9001,
                        "other_arr": [
                          "ignition: 1",
                          "totaldistance: 1000"
                        ],
                        "other_array": {
                          "ignition": "1",
                          "totaldistance": "1000"
                        },
                        "popup_sensors": {
                          "70001": {
                            "name": "Bateria",
                            "value": "87 %"
                          }
                        },
                        "sensors_value": {
                          "70001": "87 %"
                        }
                      },
                      {
                        "id": 1001,
                        "altitude": 401,
                        "course": 90,
                        "latitude": -17.779,
                        "longitude": -63.179,
                        "other": "<info><ignition>1</ignition><totaldistance>1000</totaldistance></info>",
                        "speed": "27.00",
                        "time": "01-10-2026 08:01:00",
                        "device_time": "2026-10-01 12:01:00",
                        "server_time": "01-10-2026 08:01:00",
                        "sensors_values": null,
                        "valid": 1,
                        "distance": 120,
                        "protocol": "gt06",
                        "device_id": 9001,
                        "other_arr": [
                          "ignition: 1",
                          "totaldistance: 1000"
                        ],
                        "other_array": {
                          "ignition": "1",
                          "totaldistance": "1000"
                        },
                        "popup_sensors": {
                          "70001": {
                            "name": "Bateria",
                            "value": "87 %"
                          }
                        },
                        "sensors_value": {
                          "70001": "87 %"
                        }
                      }
                    ],
                    "first_page_url": "https://plataforma.example.invalid/api/get_history_messages?page=1",
                    "from": 1,
                    "last_page": 3,
                    "last_page_url": "https://plataforma.example.invalid/api/get_history_messages?page=3",
                    "links": [],
                    "next_page_url": "https://plataforma.example.invalid/api/get_history_messages?page=2",
                    "path": "https://plataforma.example.invalid/api/get_history_messages",
                    "per_page": 50,
                    "prev_page_url": null,
                    "to": 2,
                    "total": 120,
                    "url": "https://plataforma.example.invalid/api/get_history_messages"
                  },
                  "sensors": [],
                  "pagination_limits": {
                    "50": 50,
                    "100": 100,
                    "200": 200,
                    "300": 300,
                    "400": 400,
                    "500": 500,
                    "1000": 1000
                  },
                  "limit": 50,
                  "sorting": "asc",
                  "parameters": {
                    "ignition": "",
                    "totaldistance": ""
                  },
                  "status": 1
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "404": {
            "description": "Dispositivo inexistente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "422": {
            "description": "Faltan device_id o fechas.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_events": {
      "get": {
        "operationId": "getEvents",
        "tags": [
          "Eventos y alertas"
        ],
        "summary": "Eventos generados por las alertas (más recientes primero)",
        "description": "Lista los eventos generados por las reglas de alerta, del más reciente al más antiguo. Sin `page` usa paginación por cursor (`items.data` y `items.next_cursor`); con `page` devuelve totales. `limit` vale 30 por defecto y 1000 como máximo. Las fechas se interpretan en la zona horaria de la cuenta; una fecha inválida no produce error y devuelve los datos sin filtrar. Requiere permiso para ver eventos.",
        "parameters": [
          {
            "name": "device_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "alert_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Tipo de evento (overspeed, zone_in…).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "date_from",
            "in": "query",
            "required": false,
            "description": "YYYY-MM-DD HH:MM:SS (zona de la cuenta).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "date_to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_from",
            "in": "query",
            "required": false,
            "description": "Sobre created_at.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Mensaje o nombre del vehículo.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Número de página.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor de la respuesta anterior (solo sin page).",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventsResponse"
                },
                "example": {
                  "status": 1,
                  "items": {
                    "data": [
                      {
                        "id": 5000,
                        "user_id": 1,
                        "device_id": 9001,
                        "geofence_id": null,
                        "poi_id": null,
                        "position_id": 700,
                        "alert_id": 12,
                        "type": "overspeed",
                        "message": "Exceso de velocidad (ficticio)",
                        "address": null,
                        "altitude": 0,
                        "course": 76,
                        "latitude": -17.78,
                        "longitude": -63.18,
                        "power": null,
                        "speed": 41,
                        "time": "01-10-2026 17:08:19",
                        "deleted": 0,
                        "created_at": "2026-10-01 21:08:21",
                        "updated_at": "2026-10-01 21:08:21",
                        "additional": {
                          "overspeed_speed": 30
                        },
                        "silent": null,
                        "name": "Exceso de velocidad",
                        "detail": "Velocidad 41 kph, limite 30 kph",
                        "geofence": null,
                        "device_name": "Camioneta de prueba 01"
                      }
                    ],
                    "path": "https://plataforma.example.invalid/api/get_events",
                    "per_page": 30,
                    "next_cursor": "eyJldmVudHMuaWQiOjQ5OTl9",
                    "next_page_url": "https://plataforma.example.invalid/api/get_events?cursor=eyJldmVudHMuaWQiOjQ5OTl9",
                    "prev_cursor": null,
                    "prev_page_url": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_alerts": {
      "get": {
        "operationId": "getAlerts",
        "tags": [
          "Eventos y alertas"
        ],
        "summary": "Reglas de alerta del usuario",
        "description": "Lista las reglas de alerta del usuario (no los eventos que dispararon). Si el usuario no tiene permiso para ver alertas devuelve `items.alerts` vacío, con HTTP 200.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertsResponse"
                },
                "example": {
                  "status": 1,
                  "items": {
                    "alerts": [
                      {
                        "id": 12,
                        "user_id": 1,
                        "active": 1,
                        "name": "Exceso de velocidad (ficticio)",
                        "type": "overspeed",
                        "for_all_user_devices": 0,
                        "schedules": null,
                        "notifications": {
                          "color": {
                            "active": "0"
                          },
                          "silent": {
                            "active": "0",
                            "input": "0"
                          },
                          "sound": {
                            "active": "1",
                            "input": "alarm1"
                          },
                          "popup": {
                            "active": "1",
                            "input": "10"
                          },
                          "push": {
                            "active": "1"
                          },
                          "email": {
                            "active": "0"
                          },
                          "webhook": {
                            "active": "0"
                          },
                          "sharing_email": {
                            "active": "0"
                          }
                        },
                        "created_at": "2026-02-24 21:09:52",
                        "updated_at": "2026-02-24 21:09:52",
                        "zone": 0,
                        "schedule": 0,
                        "command": {
                          "active": "0",
                          "type": "custom"
                        },
                        "continuous_duration": 0,
                        "devices": [
                          9001,
                          9002
                        ],
                        "drivers": [],
                        "geofences": [],
                        "events_custom": [],
                        "overspeed": 30
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_alerts_summary": {
      "get": {
        "operationId": "getAlertsSummary",
        "tags": [
          "Eventos y alertas"
        ],
        "summary": "Conteo de eventos por tipo de alerta",
        "description": "Cuenta los eventos agrupados por tipo. `date_from` y `date_to` se comparan sin conversión de zona horaria (UTC) contra la fecha de creación del evento. Solo acepta GET y requiere permiso para ver eventos.",
        "parameters": [
          {
            "name": "date_from",
            "in": "query",
            "required": false,
            "description": "created_at >= (UTC).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "date_to",
            "in": "query",
            "required": false,
            "description": "created_at <= (UTC).",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertsSummaryResponse"
                },
                "example": {
                  "status": 1,
                  "items": [
                    {
                      "type": "overspeed",
                      "title": "Overspeed",
                      "count": 18
                    },
                    {
                      "type": "zone_in",
                      "title": "Geofence in",
                      "count": 4
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_geofences": {
      "get": {
        "operationId": "getGeofences",
        "tags": [
          "Geocercas y rutas"
        ],
        "summary": "Geocercas del usuario",
        "description": "Lista los polígonos y círculos propios del usuario. `coordinates` es una cadena JSON que debes decodificar. Si el usuario no tiene permiso, devuelve `items.geofences` vacío.",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeofencesResponse"
                },
                "example": {
                  "items": {
                    "geofences": [
                      {
                        "id": 301,
                        "user_id": 1,
                        "group_id": 0,
                        "active": 1,
                        "name": "Base ficticia",
                        "coordinates": "[{\"lat\":-17.78,\"lng\":-63.19},{\"lat\":-17.78,\"lng\":-63.17},{\"lat\":-17.79,\"lng\":-63.17},{\"lat\":-17.79,\"lng\":-63.19}]",
                        "polygon_color": "#d000df",
                        "created_at": "2026-02-24 21:09:52",
                        "updated_at": "2026-02-24 21:09:52",
                        "type": "polygon",
                        "radius": null,
                        "center": null,
                        "device_id": null,
                        "speed_limit": 0,
                        "diem_rate_id": null,
                        "additional": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/point_in_geofences": {
      "get": {
        "operationId": "pointInGeofences",
        "tags": [
          "Geocercas y rutas"
        ],
        "summary": "Geocercas que contienen un punto",
        "description": "Devuelve los nombres de las geocercas del usuario que contienen el punto (`lat`, `lng`). Límite de 30 peticiones por minuto. Si faltan `lat` o `lng`, responde HTTP 200 con `{status: 0, errors}`; si el usuario no tiene geocercas, responde 404.",
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "required": true,
            "description": "Latitud.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "lng",
            "in": "query",
            "required": true,
            "description": "Longitud.",
            "schema": {
              "type": "number"
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK, o error de validación con HTTP 200.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PointInGeofencesResponse"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorValidationHttp200"
                    }
                  ]
                },
                "example": {
                  "status": 1,
                  "zones": [
                    "Base ficticia"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "404": {
            "description": "El usuario no tiene geocercas.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "429": {
            "description": "Límite de peticiones superado (inferido del comportamiento estándar; no medido)."
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-rate-limit": {
          "limit": 30,
          "window": "1 min"
        },
        "x-estado": "parcial",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta y código confirmados en producción. La validación y el límite de peticiones se midieron en un entorno de pruebas; la respuesta 200 solo se leyó del código porque ese entorno no podía calcularla."
      }
    },
    "/api/devices_in_geofences": {
      "get": {
        "operationId": "devicesInGeofences",
        "tags": [
          "Geocercas y rutas"
        ],
        "summary": "Geocercas que contienen la posición actual de un vehículo",
        "description": "Igual que `point_in_geofences`, pero usa la última posición de un vehículo del usuario. Límite de 1800 peticiones por minuto. Responde 404 si el usuario no tiene geocercas.",
        "parameters": [
          {
            "name": "device_id",
            "in": "query",
            "required": true,
            "description": "ID del vehículo (campo id de get_devices).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PointInGeofencesResponse"
                },
                "example": {
                  "status": 1,
                  "zones": [
                    "Base ficticia"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "404": {
            "description": "El usuario no tiene geocercas.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-rate-limit": {
          "limit": 1800,
          "window": "1 min"
        },
        "x-estado": "parcial",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta y código confirmados en producción. La respuesta 200 no se midió; se leyó del código."
      }
    },
    "/api/get_routes": {
      "get": {
        "operationId": "getRoutes",
        "tags": [
          "Geocercas y rutas"
        ],
        "summary": "Rutas planificadas",
        "description": "Lista las rutas de referencia que dibujó el usuario (no es el recorrido real), 500 por página. Requiere permiso para ver rutas.",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Número de página.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoutesResponse"
                },
                "example": {
                  "data": [],
                  "pagination": {
                    "total": 0,
                    "per_page": 500,
                    "current_page": 1,
                    "last_page": 1,
                    "next_page_url": null,
                    "prev_page_url": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "parcial",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción. La forma de `data[]` no se midió porque el entorno de pruebas no tenía rutas."
      }
    },
    "/api/get_reports": {
      "get": {
        "operationId": "getReports",
        "tags": [
          "Reportes"
        ],
        "summary": "Plantillas de reporte guardadas",
        "description": "Lista las plantillas de reporte guardadas por el usuario. No genera reportes. `limit` vale 10 por defecto.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Número de página.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportsResponse"
                },
                "example": {
                  "status": 1,
                  "items": {
                    "reports": {
                      "current_page": 1,
                      "data": [],
                      "first_page_url": "https://plataforma.example.invalid/api/get_reports?page=1",
                      "from": null,
                      "last_page": 1,
                      "last_page_url": "https://plataforma.example.invalid/api/get_reports?page=1",
                      "links": [],
                      "next_page_url": null,
                      "path": "https://plataforma.example.invalid/api/get_reports",
                      "per_page": 10,
                      "prev_page_url": null,
                      "to": null,
                      "total": 0
                    },
                    "types": [
                      {
                        "id": 1,
                        "title": "General information"
                      },
                      {
                        "id": 2,
                        "title": "Stops"
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_reports_types": {
      "get": {
        "operationId": "getReportsTypes",
        "tags": [
          "Reportes"
        ],
        "summary": "Tipos de reporte habilitados para la cuenta",
        "description": "Catálogo de los tipos de reporte disponibles para la cuenta: id, nombre, formatos, campos y reglas de validación. La respuesta es grande: unos 128 KB en una cuenta de pruebas con 79 tipos.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportTypesResponse"
                },
                "example": {
                  "status": 1,
                  "items": [
                    {
                      "type": 1,
                      "name": "General information",
                      "formats": [
                        "html",
                        "xls",
                        "pdf",
                        "pdf_land",
                        "json",
                        "csv"
                      ],
                      "fields": [
                        "date_from",
                        "date_to"
                      ],
                      "validation": {
                        "type": "required"
                      },
                      "parameters": []
                    },
                    {
                      "type": 2,
                      "name": "Stops",
                      "formats": [
                        "html",
                        "xls",
                        "pdf"
                      ],
                      "fields": [
                        "date_from",
                        "date_to",
                        "stops"
                      ],
                      "validation": {
                        "type": "required"
                      },
                      "parameters": []
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/get_user_drivers": {
      "get": {
        "operationId": "getUserDrivers",
        "tags": [
          "Cuenta"
        ],
        "summary": "Conductores del usuario",
        "description": "Lista los conductores del usuario, paginados (`limit` vale 10 por defecto). Requiere permiso para ver conductores.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Número de página.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DriversResponse"
                },
                "example": {
                  "status": 1,
                  "items": {
                    "drivers": {
                      "current_page": 1,
                      "data": [
                        {
                          "id": 21,
                          "user_id": 1,
                          "device_id": null,
                          "name": "Conductor de prueba",
                          "rfid": "0000000001",
                          "phone": "5550000000",
                          "email": "conductor@example.invalid",
                          "description": null,
                          "created_at": "2026-01-01 00:00:00",
                          "updated_at": "2026-01-01 00:00:00"
                        }
                      ],
                      "first_page_url": "https://plataforma.example.invalid/api/get_user_drivers?page=1",
                      "from": 1,
                      "last_page": 1,
                      "last_page_url": "https://plataforma.example.invalid/api/get_user_drivers?page=1",
                      "links": [],
                      "next_page_url": null,
                      "path": "https://plataforma.example.invalid/api/get_user_drivers",
                      "per_page": 10,
                      "prev_page_url": null,
                      "to": 1,
                      "total": 1
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    },
    "/api/sent_commands": {
      "get": {
        "operationId": "getSentCommands",
        "tags": [
          "Cuenta"
        ],
        "summary": "Historial de comandos enviados a los equipos",
        "description": "Historial de los comandos enviados a los equipos, 15 por página. Es solo lectura: no envía ningún comando. Requiere permiso para ver comandos.",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Número de página.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "$ref": "#/components/parameters/Lang"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SentCommandsResponse"
                },
                "example": {
                  "data": [
                    {
                      "id": 401,
                      "user_id": 1,
                      "imei": "999000000000001",
                      "connection": "gprs",
                      "command_title": "Posicion unica (ficticio)",
                      "parameters": {
                        "data": "WHERE#"
                      },
                      "response": "OK",
                      "status": 1,
                      "created_at": "01-10-2026 09:00:00",
                      "updated_at": "01-10-2026 09:00:05"
                    }
                  ],
                  "pagination": {
                    "total": 1,
                    "per_page": 15,
                    "current_page": 1,
                    "last_page": 1,
                    "next_page_url": null,
                    "prev_page_url": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "Hash ausente o incorrecto, usuario inactivo, suscripción vencida (también la del gerente) o API deshabilitada por falta de pago del servidor. HTTP 401 con `{status: 0, message}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorAuth"
                },
                "example": {
                  "status": 0,
                  "message": "Wrong credentials."
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          },
          "500": {
            "description": "Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorStandard"
                }
              }
            }
          }
        },
        "x-estado": "verificado",
        "x-verificado": "2026-10-05",
        "x-verificacion": "Ruta confirmada en producción y archivos del flujo idénticos a los verificados (comparación por huella y diff). La forma de la respuesta se midió con datos ficticios en un entorno de pruebas; no se probó con una cuenta real de producción."
      }
    }
  },
  "components": {
    "securitySchemes": {
      "UserApiHashHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "user-api-hash",
        "description": "Hash devuelto por POST /api/login. Recomendado."
      },
      "UserApiHashQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "user_api_hash",
        "description": "Misma credencial por query/cuerpo. Evítalo: queda en los registros de acceso."
      }
    },
    "parameters": {
      "Lang": {
        "name": "lang",
        "in": "query",
        "required": false,
        "description": "Idioma de los textos traducibles (SetLang). También se admite la cabecera Accept-Language.",
        "schema": {
          "type": "string",
          "examples": [
            "es",
            "en"
          ]
        }
      }
    },
    "schemas": {
      "ErrorAuth": {
        "type": "object",
        "description": "Fallo de autenticación (hash ausente, desconocido, usuario inactivo o suscripción vencida). HTTP 401.",
        "properties": {
          "status": {
            "const": 0
          },
          "message": {
            "type": "string",
            "description": "Texto traducido según el idioma de la petición (lang / Accept-Language), p. ej. \"Wrong credentials.\"."
          }
        },
        "required": [
          "status",
          "message"
        ],
        "additionalProperties": true
      },
      "ErrorStandard": {
        "type": "object",
        "description": "Forma de error del Handler de la plataforma (403, 404, 422, 500).",
        "properties": {
          "statusCode": {
            "type": "integer",
            "description": "Igual al código HTTP."
          },
          "message": {
            "type": "string"
          },
          "status": {
            "const": 0
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Por campo; para errores no de campo la clave es \"id\"."
          },
          "perm": {
            "const": 0,
            "description": "Solo en 403."
          }
        },
        "required": [
          "statusCode",
          "message",
          "status"
        ],
        "additionalProperties": true
      },
      "ErrorValidationHttp200": {
        "type": "object",
        "description": "Algunos endpoints devuelven errores de validación con HTTP 200 (p. ej. point_in_geofences sin lat/lng). Comprueba SIEMPRE \"status\".",
        "properties": {
          "status": {
            "const": 0
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        "required": [
          "status",
          "errors"
        ],
        "additionalProperties": true
      },
      "PermissionTriplet": {
        "type": "object",
        "properties": {
          "view": {
            "type": "boolean"
          },
          "edit": {
            "type": "boolean"
          },
          "remove": {
            "type": "boolean"
          }
        },
        "required": [
          "view",
          "edit",
          "remove"
        ],
        "additionalProperties": true
      },
      "Paginator": {
        "type": "object",
        "description": "Paginador con totales.",
        "properties": {
          "current_page": {
            "type": "integer"
          },
          "data": {
            "type": "array",
            "items": {}
          },
          "first_page_url": {
            "type": "string"
          },
          "from": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_page": {
            "type": "integer"
          },
          "last_page_url": {
            "type": "string"
          },
          "links": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "label": {
                  "type": "string"
                },
                "active": {
                  "type": "boolean"
                }
              },
              "additionalProperties": true
            }
          },
          "next_page_url": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "path": {
            "type": "string"
          },
          "per_page": {
            "type": "integer"
          },
          "prev_page_url": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "total": {
            "type": "integer"
          }
        },
        "required": [
          "current_page",
          "data",
          "last_page",
          "per_page",
          "total"
        ],
        "additionalProperties": true
      },
      "CursorPaginator": {
        "type": "object",
        "description": "Paginador por cursor (más rápido; sin total).",
        "properties": {
          "data": {
            "type": "array",
            "items": {}
          },
          "path": {
            "type": "string"
          },
          "per_page": {
            "type": "integer"
          },
          "next_cursor": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "next_page_url": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "prev_cursor": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "prev_page_url": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "data",
          "per_page",
          "next_cursor"
        ],
        "additionalProperties": true
      },
      "LoginResponse": {
        "type": "object",
        "properties": {
          "status": {
            "const": 1
          },
          "user_api_hash": {
            "type": "string",
            "description": "Credencial de la API. Larga vida: solo cambia si se cambia la contraseña del usuario."
          },
          "permissions": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/PermissionTriplet"
            }
          }
        },
        "required": [
          "status",
          "user_api_hash"
        ],
        "additionalProperties": true
      },
      "UserData": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "expiration_date": {
            "oneOf": [
              {
                "type": "string",
                "description": "Vencimiento de la suscripción. Zona horaria: la de la cuenta del usuario de la API, no UTC. Formato de visualización: el configurado en la cuenta (en las mediciones fue dd-mm-YYYY HH:mm:ss)."
              },
              {
                "type": "null"
              }
            ]
          },
          "days_left": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "plan": {
            "type": "string"
          },
          "devices_limit": {
            "type": "integer"
          },
          "group_id": {
            "type": "integer",
            "description": "1 admin, 2 usuario/cliente, 3 gerente (reseller), 4 demo, 5 operador, 6 supervisor; 7 = financiero (solo en producción)."
          },
          "role_id": {
            "type": "integer"
          },
          "permissions": {
            "type": "object",
            "description": "Módulo -> {view,edit,remove}. Incluye claves como \"devices\", \"history\", \"device.imei\".",
            "additionalProperties": {
              "$ref": "#/components/schemas/PermissionTriplet"
            }
          }
        },
        "required": [
          "email",
          "devices_limit",
          "group_id",
          "permissions"
        ],
        "additionalProperties": true
      },
      "DeviceSensorValue": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "type": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "show_in_popup": {
            "type": "integer"
          },
          "value": {
            "type": "string",
            "description": "Valor formateado con unidad (ya HTML-escapado)."
          },
          "val": {
            "description": "Valor numérico/booleano/texto sin formato; null si el sensor no tiene valor."
          },
          "scale_value": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "tag_name": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "type",
          "name",
          "value"
        ],
        "additionalProperties": true
      },
      "DeviceServiceValue": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "value": {
            "type": "string",
            "description": "Texto legible: p. ej. \"Days Left (56d.)\"."
          },
          "expiring": {
            "type": "boolean"
          },
          "expiration_by": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "additionalProperties": true
      },
      "DeviceBase": {
        "type": "object",
        "description": "Campos comunes de un vehículo (sin sensors/services/tail, que difieren entre endpoints).",
        "properties": {
          "id": {
            "type": "integer"
          },
          "alarm": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "online": {
            "type": "string",
            "enum": [
              "online",
              "offline",
              "ack",
              "engine",
              "blocked"
            ],
            "description": "Estado calculado (la plataforma): online=en movimiento, engine=motor encendido detenido, ack=detenido, offline, blocked."
          },
          "time": {
            "type": "string",
            "description": "Texto de \"última hora de contacto\": max(última posición, último paquete). Puede ser una ETIQUETA traducida (\"No conectado\", \"Deshabilitado\", \"Vencido\") en lugar de una fecha. Zona horaria: la de la cuenta del usuario de la API, no UTC. Formato de visualización: el configurado en la cuenta (en las mediciones fue dd-mm-YYYY HH:mm:ss)."
          },
          "no_position_update": {
            "type": "boolean",
            "description": "Presente en producción. true = el equipo está conectado pero su última posición válida es > 15 min más vieja que su último latido."
          },
          "last_position_time": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Presente en producción. Hora de la última posición válida con formato de la cuenta; null si no hay."
          },
          "timestamp": {
            "type": "integer",
            "description": "Segundos Unix UTC de la última POSICIÓN."
          },
          "acktimestamp": {
            "type": "integer",
            "description": "Segundos Unix UTC del último paquete/latido."
          },
          "lat": {
            "type": "number",
            "description": "Última posición válida (grados decimales)."
          },
          "lng": {
            "type": "number"
          },
          "course": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "const": "-"
              }
            ],
            "description": "Rumbo en grados; \"-\" si no hay."
          },
          "speed": {
            "type": "integer",
            "description": "En la unidad de la cuenta (ver distance_unit_hour)."
          },
          "altitude": {
            "type": "integer"
          },
          "icon_type": {
            "type": "string"
          },
          "icon_color": {
            "type": "string"
          },
          "icon_colors": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "icon": {
            "type": "object",
            "additionalProperties": true
          },
          "power": {
            "type": "string"
          },
          "address": {
            "type": "string",
            "description": "\"-\" si no hay dirección resuelta."
          },
          "protocol": {
            "type": "string",
            "description": "Protocolo detectado (gt06, h02, jt808…) o \"-\" si el rol no puede verlo."
          },
          "driver": {
            "type": "string"
          },
          "driver_data": {
            "type": "object",
            "additionalProperties": true
          },
          "distance_unit_hour": {
            "type": "string",
            "description": "Unidad de velocidad, p. ej. \"kph\"."
          },
          "unit_of_distance": {
            "type": "string",
            "description": "p. ej. \"Km\"."
          },
          "unit_of_altitude": {
            "type": "string"
          },
          "unit_of_capacity": {
            "type": "string"
          },
          "stop_duration": {
            "type": "string",
            "description": "Texto, \"-\" si no aplica."
          },
          "stop_duration_sec": {
            "type": "integer"
          },
          "moved_timestamp": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "engine_status": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ]
          },
          "detect_engine": {
            "type": "string"
          },
          "engine_hours": {
            "type": "string"
          },
          "total_distance": {
            "type": "number",
            "description": "En unidad de la cuenta."
          },
          "inaccuracy": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "sim_expiration_date": {
            "type": "string"
          },
          "device_data": {
            "type": "object",
            "additionalProperties": true,
            "description": "Registro completo del dispositivo (incluye imei, plate_number, sim_number…). Campos sujetos a los permisos del rol (device.imei, device.sim_number…): si no hay permiso llegan en null. NO exhaustivo aquí."
          }
        },
        "required": [
          "id",
          "name",
          "online",
          "time",
          "timestamp",
          "lat",
          "lng",
          "speed",
          "device_data"
        ],
        "additionalProperties": true
      },
      "Device": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DeviceBase"
          },
          {
            "type": "object",
            "properties": {
              "sensors": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DeviceSensorValue"
                }
              },
              "services": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DeviceServiceValue"
                }
              },
              "tail": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "lat": {
                      "type": "string"
                    },
                    "lng": {
                      "type": "string"
                    }
                  },
                  "additionalProperties": true
                },
                "description": "Últimas posiciones (cola); lat/lng como cadenas."
              }
            },
            "required": [
              "sensors"
            ],
            "additionalProperties": true
          }
        ],
        "description": "Vehículo en get_devices."
      },
      "DeviceGroup": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Device"
            }
          }
        },
        "required": [
          "id",
          "title",
          "items"
        ],
        "additionalProperties": true
      },
      "DeviceLatest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DeviceBase"
          },
          {
            "type": "object",
            "properties": {
              "sensors": {
                "type": "string",
                "description": "CADENA JSON con la lista de sensores: hay que hacer JSON.parse."
              },
              "services": {
                "type": "string",
                "description": "CADENA JSON."
              },
              "tail": {
                "type": "string",
                "description": "CADENA JSON."
              }
            },
            "required": [
              "sensors"
            ],
            "additionalProperties": true
          }
        ],
        "description": "Vehículo en get_devices_latest: igual que Device pero sensors/services/tail llegan como CADENAS JSON."
      },
      "DevicesLatestResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeviceLatest"
            }
          },
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "Evento reciente con los campos (id, type, message, time, speed, sound, color, delay, device{id,name}, geofence{id,name}). Forma no medida: estuvo vacío en las mediciones.",
              "properties": {},
              "additionalProperties": true
            }
          },
          "time": {
            "type": "integer",
            "description": "Segundos Unix del servidor: úsalo como \"time\" de la siguiente consulta."
          },
          "version": {
            "type": "string"
          }
        },
        "required": [
          "items",
          "events",
          "time"
        ],
        "additionalProperties": true
      },
      "HistoryPoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "device_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "item_id": {
            "type": "string"
          },
          "time": {
            "type": "string",
            "description": "Hora de la posición. Zona horaria: la de la cuenta del usuario de la API, no UTC. Formato de visualización: el configurado en la cuenta (en las mediciones fue dd-mm-YYYY HH:mm:ss)."
          },
          "raw_time": {
            "type": "string",
            "description": "YYYY-MM-DD HH:MM:SS en la zona de la cuenta."
          },
          "altitude": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "course": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "speed": {
            "type": "number",
            "description": "Unidad de la cuenta."
          },
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          },
          "lat": {
            "type": "number"
          },
          "lng": {
            "type": "number"
          },
          "distance": {
            "type": "number"
          },
          "other": {
            "type": "string",
            "description": "XML crudo de atributos del equipo."
          },
          "color": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "valid": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "device_time": {
            "type": "string",
            "description": "CRUDO, en UTC (YYYY-MM-DD HH:MM:SS)."
          },
          "server_time": {
            "type": "string",
            "description": "CRUDO, en UTC."
          },
          "other_arr": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sensors_data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "\"speed\", \"altitude\" o \"sensor_<id>\"."
                },
                "value": {
                  "type": "number"
                }
              },
              "additionalProperties": true
            }
          }
        },
        "required": [
          "id",
          "lat",
          "lng",
          "raw_time"
        ],
        "additionalProperties": true
      },
      "HistoryItem": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer",
            "enum": [
              1,
              2,
              3,
              4,
              5
            ],
            "description": "1=conducción, 2=parada, 3=inicio, 4=fin, 5=evento."
          },
          "index": {
            "type": "integer"
          },
          "time": {
            "oneOf": [
              {
                "type": "string",
                "description": "Duración legible, p. ej. \"40min 0s\"."
              },
              {
                "type": "null"
              }
            ]
          },
          "show": {
            "type": "string",
            "description": "Inicio con formato de cuenta."
          },
          "left": {
            "type": "string",
            "description": "Fin con formato de cuenta."
          },
          "raw_time": {
            "type": "string"
          },
          "distance": {
            "type": "number",
            "description": "Unidad de la cuenta."
          },
          "time_seconds": {
            "type": "integer"
          },
          "engine_work": {
            "type": "integer"
          },
          "engine_idle": {
            "type": "integer"
          },
          "engine_hours": {
            "type": "integer"
          },
          "fuel_consumption": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "top_speed": {
            "type": "integer"
          },
          "average_speed": {
            "type": "integer"
          },
          "driver": {
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ]
          },
          "message": {
            "type": "string",
            "description": "Solo status=5."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HistoryPoint"
            }
          }
        },
        "required": [
          "status",
          "raw_time",
          "items"
        ],
        "additionalProperties": true
      },
      "HistoryResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HistoryItem"
            }
          },
          "device": {
            "type": "object",
            "additionalProperties": true,
            "description": "Vehículo consultado, con sus sensores."
          },
          "distance_sum": {
            "type": "string",
            "description": "Con unidad: \"9.2 Km\"."
          },
          "top_speed": {
            "type": "string",
            "description": "\"31 kph\"."
          },
          "move_duration": {
            "type": "string"
          },
          "stop_duration": {
            "type": "string"
          },
          "engine_hours": {
            "type": "string"
          },
          "engine_idle": {
            "type": "string"
          },
          "engine_work": {
            "type": "string"
          },
          "fuel_consumption": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "sensors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "sufix": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "additionalProperties": true
            }
          },
          "fuel_consumption_arr": {
            "type": "array",
            "items": {}
          },
          "item_class": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "value": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              },
              "additionalProperties": true
            }
          },
          "images": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "value": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              },
              "additionalProperties": true
            }
          },
          "status": {
            "const": 1
          }
        },
        "required": [
          "items",
          "device",
          "distance_sum",
          "sensors",
          "status"
        ],
        "additionalProperties": true
      },
      "PositionMessage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "altitude": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "course": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          },
          "other": {
            "type": "string"
          },
          "speed": {
            "type": "string",
            "description": "Cadena numérica formateada, p. ej. \"27.00\"."
          },
          "time": {
            "type": "string",
            "description": "Con formato de cuenta. Zona horaria: la de la cuenta del usuario de la API, no UTC. Formato de visualización: el configurado en la cuenta (en las mediciones fue dd-mm-YYYY HH:mm:ss)."
          },
          "device_time": {
            "type": "string",
            "description": "CRUDO UTC."
          },
          "server_time": {
            "type": "string",
            "description": "Con formato de cuenta."
          },
          "sensors_values": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "valid": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "distance": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "protocol": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "device_id": {
            "type": "integer"
          },
          "other_arr": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "other_array": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "popup_sensors": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              },
              "additionalProperties": true
            }
          },
          "sensors_value": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "latitude",
          "longitude",
          "time"
        ],
        "additionalProperties": true
      },
      "PositionMessagesResponse": {
        "type": "object",
        "properties": {
          "messages": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Paginator"
              },
              {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/PositionMessage"
                    }
                  },
                  "url": {
                    "type": "string"
                  }
                },
                "additionalProperties": true
              }
            ]
          },
          "sensors": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "pagination_limits": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "limit": {
            "type": "integer"
          },
          "sorting": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ]
          },
          "parameters": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "status": {
            "const": 1
          }
        },
        "required": [
          "messages",
          "limit",
          "sorting",
          "status"
        ],
        "additionalProperties": true
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "device_id": {
            "type": "integer"
          },
          "geofence_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "poi_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "position_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "alert_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "type": {
            "type": "string",
            "description": "overspeed, zone_in, zone_out, sos, ignition_on/off, move_start, stop_duration, offline_duration, custom, …"
          },
          "message": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "address": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "altitude": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "course": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "latitude": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "longitude": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "power": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "speed": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "time": {
            "type": "string",
            "description": "Hora del evento con formato de cuenta. Zona horaria: la de la cuenta del usuario de la API, no UTC. Formato de visualización: el configurado en la cuenta (en las mediciones fue dd-mm-YYYY HH:mm:ss)."
          },
          "deleted": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "description": "CRUDO UTC."
          },
          "updated_at": {
            "type": "string",
            "description": "CRUDO UTC."
          },
          "additional": {
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ]
          },
          "silent": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "detail": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "geofence": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "integer"
                  },
                  "name": {
                    "type": "string"
                  }
                },
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ]
          },
          "device_name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "device_id",
          "type",
          "time"
        ],
        "additionalProperties": true
      },
      "EventsResponse": {
        "type": "object",
        "properties": {
          "status": {
            "const": 1
          },
          "items": {
            "oneOf": [
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Paginator"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "data": {
                        "type": "array",
                        "items": {
                          "$ref": "#/components/schemas/Event"
                        }
                      }
                    },
                    "additionalProperties": true
                  }
                ]
              },
              {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/CursorPaginator"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "data": {
                        "type": "array",
                        "items": {
                          "$ref": "#/components/schemas/Event"
                        }
                      }
                    },
                    "additionalProperties": true
                  }
                ]
              }
            ],
            "description": "Con ?page= devuelve Paginator; sin page, CursorPaginator."
          }
        },
        "required": [
          "status",
          "items"
        ],
        "additionalProperties": true
      },
      "Alert": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "active": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "for_all_user_devices": {
            "type": "integer"
          },
          "schedules": {
            "description": "Horarios de la alerta; null en las mediciones (forma no medida)."
          },
          "notifications": {
            "type": "object",
            "additionalProperties": true,
            "description": "Canales (color, silent, sound, popup, push, email, webhook, sharing_email) con {active:\"0\"|\"1\", input?}."
          },
          "created_at": {
            "type": "string",
            "description": "CRUDO UTC."
          },
          "updated_at": {
            "type": "string"
          },
          "zone": {
            "type": "integer"
          },
          "schedule": {
            "type": "integer"
          },
          "command": {
            "type": "object",
            "additionalProperties": true
          },
          "continuous_duration": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "devices": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "IDs de vehículos."
          },
          "drivers": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "geofences": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "events_custom": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "overspeed": {
            "type": "integer",
            "description": "Presente en alertas de exceso de velocidad (campo añadido por tipo)."
          }
        },
        "required": [
          "id",
          "name",
          "type",
          "active"
        ],
        "additionalProperties": true
      },
      "AlertsResponse": {
        "type": "object",
        "properties": {
          "status": {
            "const": 1
          },
          "items": {
            "type": "object",
            "properties": {
              "alerts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            },
            "required": [
              "alerts"
            ],
            "additionalProperties": true
          }
        },
        "required": [
          "status",
          "items"
        ],
        "additionalProperties": true
      },
      "AlertsSummaryResponse": {
        "type": "object",
        "properties": {
          "status": {
            "const": 1
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              },
              "required": [
                "type",
                "count"
              ],
              "additionalProperties": true
            }
          }
        },
        "required": [
          "status",
          "items"
        ],
        "additionalProperties": true
      },
      "Geofence": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "group_id": {
            "type": "integer"
          },
          "active": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "coordinates": {
            "type": "string",
            "description": "CADENA JSON: [{\"lat\":..,\"lng\":..},…] (polígono). Hay que hacer JSON.parse."
          },
          "polygon_color": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "description": "CRUDO UTC."
          },
          "updated_at": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "polygon",
              "circle"
            ]
          },
          "radius": {
            "oneOf": [
              {
                "type": "number",
                "description": "Metros; solo círculos."
              },
              {
                "type": "null"
              }
            ]
          },
          "center": {
            "oneOf": [
              {
                "type": "string",
                "description": "Solo círculos; formato no medido."
              },
              {
                "type": "null"
              }
            ]
          },
          "device_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "speed_limit": {
            "type": "integer"
          },
          "diem_rate_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "additional": {
            "description": "Datos adicionales; null en las mediciones (forma no medida)."
          }
        },
        "required": [
          "id",
          "name",
          "type",
          "coordinates"
        ],
        "additionalProperties": true
      },
      "GeofencesResponse": {
        "type": "object",
        "description": "Sin clave \"status\". Si el usuario no tiene permiso, devuelve items.geofences=[] (el error se silencia).",
        "properties": {
          "items": {
            "type": "object",
            "properties": {
              "geofences": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Geofence"
                }
              }
            },
            "required": [
              "geofences"
            ],
            "additionalProperties": true
          }
        },
        "required": [
          "items"
        ],
        "additionalProperties": true
      },
      "RoutesResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "coordinates: forma no medida (la lista estuvo vacía).",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "group_id": {
                  "type": "integer"
                },
                "active": {
                  "type": "integer"
                },
                "name": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                },
                "coordinates": {}
              },
              "additionalProperties": true
            }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "per_page": {
                "type": "integer"
              },
              "current_page": {
                "type": "integer"
              },
              "last_page": {
                "type": "integer"
              },
              "next_page_url": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "prev_page_url": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "additionalProperties": true
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "additionalProperties": true
      },
      "PointInGeofencesResponse": {
        "type": "object",
        "properties": {
          "status": {
            "const": 1
          },
          "zones": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Nombres de las geocercas que contienen el punto."
          }
        },
        "required": [
          "status",
          "zones"
        ],
        "additionalProperties": true
      },
      "ReportType": {
        "type": "object",
        "properties": {
          "type": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "formats": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "validation": {
            "type": "object",
            "additionalProperties": true
          },
          "parameters": {
            "type": "array",
            "items": {}
          }
        },
        "required": [
          "type",
          "name",
          "formats"
        ],
        "additionalProperties": true
      },
      "ReportTypesResponse": {
        "type": "object",
        "properties": {
          "status": {
            "const": 1
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReportType"
            }
          }
        },
        "required": [
          "status",
          "items"
        ],
        "additionalProperties": true
      },
      "ReportsResponse": {
        "type": "object",
        "properties": {
          "status": {
            "const": 1
          },
          "items": {
            "type": "object",
            "properties": {
              "reports": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Paginator"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "data": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "additionalProperties": true
                        }
                      }
                    },
                    "additionalProperties": true
                  }
                ]
              },
              "types": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "title": {
                      "type": "string"
                    }
                  },
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "reports",
              "types"
            ],
            "additionalProperties": true
          }
        },
        "required": [
          "status",
          "items"
        ],
        "additionalProperties": true
      },
      "Driver": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "device_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "rfid": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "phone": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "email": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "description": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "additionalProperties": true
      },
      "DriversResponse": {
        "type": "object",
        "properties": {
          "status": {
            "const": 1
          },
          "items": {
            "type": "object",
            "properties": {
              "drivers": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Paginator"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "data": {
                        "type": "array",
                        "items": {
                          "$ref": "#/components/schemas/Driver"
                        }
                      }
                    },
                    "additionalProperties": true
                  }
                ]
              }
            },
            "required": [
              "drivers"
            ],
            "additionalProperties": true
          }
        },
        "required": [
          "status",
          "items"
        ],
        "additionalProperties": true
      },
      "SentCommand": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "imei": {
            "type": "string"
          },
          "connection": {
            "type": "string",
            "description": "gprs | sms"
          },
          "command_title": {
            "type": "string"
          },
          "parameters": {
            "type": "object",
            "additionalProperties": true
          },
          "response": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "description": "Con formato de cuenta."
          },
          "updated_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "imei",
          "command_title"
        ],
        "additionalProperties": true
      },
      "SentCommandsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SentCommand"
            }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "per_page": {
                "type": "integer"
              },
              "current_page": {
                "type": "integer"
              },
              "last_page": {
                "type": "integer"
              },
              "next_page_url": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "prev_page_url": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "additionalProperties": true
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "additionalProperties": true
      }
    }
  }
}
