> Índice completo de la documentación: https://trackerintl.com/devs/llms.txt
> Esta página en HTML: https://trackerintl.com/devs/referencia/dispositivos
> Estado: Verificado, revisada el 2026-10-05. Verificado por lectura del código y diff contra producción; las respuestas se midieron con datos ficticios en un entorno de pruebas. No probado con una cuenta real.

# Dispositivos

Lista tus vehículos con su última posición y estado, y consulta solo los que cambiaron desde un instante. Parámetros, respuestas y ejemplos.

En la API, cada **vehículo** es un *dispositivo* (`device`): un equipo GPS asociado a un vehículo de tu cuenta. Su campo `id` es el que usas como `device_id` en el resto de las operaciones.

## Estado del vehículo

El campo `online` resume el estado calculado por la plataforma:

| Valor | Significado |
|---|---|
| `online` | En movimiento |
| `engine` | Motor encendido y detenido |
| `ack` | Detenido |
| `offline` | Sin conexión |
| `blocked` | Bloqueado |

El campo `time` es una etiqueta de la última hora de contacto y puede ser un texto traducido, como "No conectado", en lugar de una fecha. Para la hora de la última posición usa `timestamp` (segundos Unix, UTC) o `last_position_time`.

## Qué lista usar

- `get_devices` para el inventario completo, con filtros por texto, IMEI, placa, grupo o estado.
- `get_devices_latest` para sondeo: devuelve solo los vehículos con posición nueva desde un instante.

En la lista de vehículos, `sensors` y `services` traen los valores actuales de cada sensor y servicio del vehículo; en `get_devices_latest` esos campos llegan como cadenas JSON.

## Listar vehículos agrupados con su última posición

**GET** `/api/get_devices` · Estado: Verificado

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.

Autenticación. Cabecera `user-api-hash` con tu `user_api_hash`.

- 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.
- Los filtros de texto (`s`) buscan en nombre, IMEI, placa y otros campos del vehículo.

### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `s` | query | string | No | Búsqueda de texto; varios términos separados por ";" (OR). Medido con valor simple. |
| `limit` | query | integer | No | Vehículos por página. Sin tope en el código (se recomienda ≤ 200). |
| `page` | query | integer | No | Página (pasar page o limit activa la paginación). |
| `device_id` | query | integer | No | Filtro por ID. |
| `id` | query | integer | No | Equivale a device_id (también filtra). |
| `imei` | query | string | No | IMEI exacto. |
| `plate_number` | query | string | No | Placa exacta. |
| `group_id` | query | integer | No | 0 = sin grupo. |
| `status` | query | string ("expired", "offline", "online", "inactive", "move", "stop", "park", "idle", "engine_on", "engine_off", "blocked", "not_connected", "never_connected") | No | Estado, puede repetirse como arreglo. |
| `online` | query | integer | No | Minutos: conectados en los últimos N minutos. |
| `offline` | query | integer | No | Minutos: sin conexión hace más de N minutos. |
| `lang` | query | string | No | Idioma de los textos traducibles (SetLang). También se admite la cabecera Accept-Language. |

### Ejemplo de solicitud

cURL:

```bash
curl -sS -G "https://plataforma.trackerintl.com/api/get_devices" \
  -H "user-api-hash: TU_API_HASH" \
  --data-urlencode "limit=50" \
  --data-urlencode "page=1"
```

JavaScript:

```javascript
const BASE_URL = "https://plataforma.trackerintl.com";
const API_HASH = "TU_API_HASH";

const params = new URLSearchParams({
  limit: "50",
  page: "1",
});
const respuesta = await fetch(`${BASE_URL}/api/get_devices?${params}`, {
  headers: { "user-api-hash": API_HASH },
});
if (!respuesta.ok) throw new Error(`HTTP ${respuesta.status}: ${await respuesta.text()}`);
console.log(JSON.stringify(await respuesta.json(), null, 2));
```

Python:

```python
import json
import requests

BASE_URL = "https://plataforma.trackerintl.com"
API_HASH = "TU_API_HASH"

respuesta = requests.get(
    f"{BASE_URL}/api/get_devices",
    headers={"user-api-hash": API_HASH},
    params={"limit": "50", "page": "1"},
    timeout=30,
)
respuesta.raise_for_status()
print(json.dumps(respuesta.json(), indent=2, ensure_ascii=False))
```

PHP:

```php
<?php
$baseUrl = "https://plataforma.trackerintl.com";
$apiHash = "TU_API_HASH";

$url = $baseUrl . "/api/get_devices?" . http_build_query(["limit" => "50", "page" => "1"]);
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => ["user-api-hash: " . $apiHash],
]);
$cuerpo = curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($cuerpo === false || $codigo !== 200) {
    fwrite(STDERR, "HTTP $codigo\n");
    exit(1);
}
echo json_encode(json_decode($cuerpo, true), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), "\n";
```

### Respuestas

| Código | Descripción |
|---|---|
| `200` | Respuesta correcta. |
| `401` | 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}`. |
| `403` | Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`. |
| `500` | Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico. |

Ejemplo de respuesta 200 (datos ficticios):

```json
[
  {
    "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
        }
      }
    ]
  }
]
```

### Verificación

Estado: Verificado. Revisado el 5 de octubre de 2026. 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.

## Vehículos con posición actualizada desde un instante (delta) + eventos recientes

**GET** `/api/get_devices_latest` · Estado: Verificado

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.

Autenticación. Cabecera `user-api-hash` con tu `user_api_hash`.

- Comparte con `get_devices` el riesgo de HTTP 500 si algún vehículo tiene el icono sin asignar.

### Parámetros

| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
| `time` | query | integer | No | Segundos Unix UTC. Por defecto ahora−5 s. Usa 1 para todo. |
| `device_id` | query | integer | No | Un vehículo. |
| `id` | query | integer | No | Un vehículo. |
| `imei` | query | string | No | IMEI. |
| `limit` | query | integer | No | Vehículos por página (por defecto 100 si se envía page). |
| `page` | query | integer | No | Página. |
| `lang` | query | string | No | Idioma de los textos traducibles (SetLang). También se admite la cabecera Accept-Language. |

### Ejemplo de solicitud

cURL:

```bash
curl -sS -G "https://plataforma.trackerintl.com/api/get_devices_latest" \
  -H "user-api-hash: TU_API_HASH" \
  --data-urlencode "time=1"
```

JavaScript:

```javascript
const BASE_URL = "https://plataforma.trackerintl.com";
const API_HASH = "TU_API_HASH";

const params = new URLSearchParams({
  time: "1",
});
const respuesta = await fetch(`${BASE_URL}/api/get_devices_latest?${params}`, {
  headers: { "user-api-hash": API_HASH },
});
if (!respuesta.ok) throw new Error(`HTTP ${respuesta.status}: ${await respuesta.text()}`);
console.log(JSON.stringify(await respuesta.json(), null, 2));
```

Python:

```python
import json
import requests

BASE_URL = "https://plataforma.trackerintl.com"
API_HASH = "TU_API_HASH"

respuesta = requests.get(
    f"{BASE_URL}/api/get_devices_latest",
    headers={"user-api-hash": API_HASH},
    params={"time": "1"},
    timeout=30,
)
respuesta.raise_for_status()
print(json.dumps(respuesta.json(), indent=2, ensure_ascii=False))
```

PHP:

```php
<?php
$baseUrl = "https://plataforma.trackerintl.com";
$apiHash = "TU_API_HASH";

$url = $baseUrl . "/api/get_devices_latest?" . http_build_query(["time" => "1"]);
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => ["user-api-hash: " . $apiHash],
]);
$cuerpo = curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($cuerpo === false || $codigo !== 200) {
    fwrite(STDERR, "HTTP $codigo\n");
    exit(1);
}
echo json_encode(json_decode($cuerpo, true), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), "\n";
```

### Respuestas

| Código | Descripción |
|---|---|
| `200` | Respuesta correcta. |
| `401` | 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}`. |
| `403` | Sin permiso del rol para el módulo, vehículo de otro usuario o cuenta restringida por facturación. Incluye `perm: 0`. |
| `500` | Error interno de la plataforma. Con la depuración apagada el texto del mensaje es genérico. |

| Campo (respuesta 200) | Tipo | Descripción |
|---|---|---|
| `items` | array de DeviceLatest |  |
| `events` | array de object |  |
| `time` | integer | Segundos Unix del servidor: úsalo como "time" de la siguiente consulta. |
| `version` | string |  |

Ejemplo de respuesta 200 (datos ficticios):

```json
{
  "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"
}
```

### Verificación

Estado: Verificado. Revisado el 5 de octubre de 2026. 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.
