Devices
Manage the GPS tracking units in your fleet — list, inspect, get real-time position, or update configuration.
All endpoints require a valid JWT token, API key, and tenant header. See Authentication.
List Devices
Retrieve a paginated list of devices with filtering support.
/apidev/v1/fleet/devicesQuery Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
limit | integer | No | 25 | Records per page. Min: 1, Max: 100 |
offset | integer | No | 0 | Records to skip |
status | string | No | — | A (active) or I (inactive) |
name | string | No | — | Partial match on device name or alias |
imei | string | No | — | Partial match on IMEI (primary or secondary) |
license_plate | string | No | — | Partial match on license plate |
device_group | string | No | — | Partial match on device group name |
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Device unique identifier (BigInt as string) |
name | string | null | Device display name |
alias | string | null | Short alias |
license_plate | string | null | Vehicle license plate |
imei_app | string | null | Primary IMEI number |
imei_gps | string | null | Secondary IMEI number |
external_id | string | null | Identifier in an external system |
active | boolean | Whether the device is currently active |
status | string | "A" (active) or "I" (inactive) |
device_group | string | null | Group or category name |
last_position | object | null | Last known GPS position (see Position fields) |
Code Example
- cURL
- JavaScript
- Python
curl -s "https://$TENANT/apidev/v1/fleet/devices?limit=10&status=A" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT"
const response = await fetch(
`https://${TENANT}/apidev/v1/fleet/devices?limit=10&status=A`,
{
headers: {
"Authorization": `Bearer ${token}`,
"X-API-Key": API_KEY,
"tenant": TENANT,
},
}
);
const { data, meta } = await response.json();
console.log(`Fetched ${data.length} of ${meta.total} devices`);
response = requests.get(
f"https://{TENANT}/apidev/v1/fleet/devices",
headers=headers,
params={"limit": 10, "status": "A"},
)
result = response.json()
for device in result["data"]:
print(f"{device['id']}: {device['name']} ({device['status']})")
Example Response
{
"success": true,
"data": [
{
"id": "104820579301",
"name": "Movil 10",
"alias": "M10",
"license_plate": "ABC123",
"imei_app": "352093081234567",
"imei_gps": "352093089876543",
"external_id": null,
"active": true,
"status": "A",
"device_group": "Trucks",
"last_position": {
"latitude": -34.9011,
"longitude": -56.1645,
"speed": 45.2,
"heading": 180,
"datetime": "2026-04-04T14:32:00",
"last_signal_at": "2026-04-04T14:32:00",
"ignition_on_at": "2026-04-04T07:15:00",
"ignition_off_at": null,
"address": "Av. 18 de Julio 1234, Montevideo",
"odometer": 84523.7,
"horometer": 3210.5
}
},
{
"id": "104820579315",
"name": "Movil 15",
"alias": null,
"license_plate": "XYZ789",
"imei_app": "352093089876543",
"imei_gps": null,
"external_id": "EXT-0015",
"active": true,
"status": "A",
"device_group": "Vans",
"last_position": null
}
],
"meta": {
"total": 42,
"limit": 10,
"offset": 0
}
}
last_position is null when the device has never reported GPS data. The list endpoint does not include satellites, battery_voltage, or external_power — use the Position endpoint for full telemetry.
Device Detail
Full profile for a single device including vehicle metadata, assigned driver, and last known position with extended telemetry.
/apidev/v1/fleet/devices/{id}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Device unique identifier |
Response Fields
All fields from List Devices, plus:
| Field | Type | Description |
|---|---|---|
image_url | string | null | URL to the device/vehicle image |
brand | string | null | Vehicle brand (e.g., Toyota, Ford) |
model | string | null | Vehicle model |
year | integer | null | Vehicle model year |
notes | string | null | Free-text notes |
driver | object | null | Assigned driver: { id, name } |
last_position | object | null | Extended position with satellites, battery_voltage, external_power (see Position fields) |
Code Example
- cURL
- JavaScript
- Python
curl -s "https://$TENANT/apidev/v1/fleet/devices/104820579301" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT"
const response = await fetch(
`https://${TENANT}/apidev/v1/fleet/devices/104820579301`,
{ headers }
);
const { data } = await response.json();
console.log(`${data.name} — ${data.driver?.name ?? 'No driver'}`);
response = requests.get(
f"https://{TENANT}/apidev/v1/fleet/devices/104820579301",
headers=headers,
)
device = response.json()["data"]
print(f"{device['name']} — {device['brand']} {device['model']}")
Example Response
{
"success": true,
"data": {
"id": "104820579301",
"name": "Movil 10",
"alias": "M10",
"license_plate": "ABC123",
"imei_app": "352093081234567",
"imei_gps": "352093089876543",
"external_id": "EXT-0042",
"active": true,
"status": "A",
"device_group": "Trucks",
"image_url": null,
"brand": "Toyota",
"model": "Hilux",
"year": 2022,
"notes": "Assigned to the northern delivery route",
"driver": {
"id": "104820579455",
"name": "Carlos Martinez"
},
"last_position": {
"latitude": -34.9011,
"longitude": -56.1645,
"speed": 45.2,
"heading": 180,
"datetime": "2026-04-04T14:32:00",
"last_signal_at": "2026-04-04T14:32:00",
"ignition_on_at": "2026-04-04T07:15:00",
"ignition_off_at": null,
"address": "Av. 18 de Julio 1234, Montevideo",
"odometer": 84523.7,
"horometer": 3210.5,
"satellites": 12,
"battery_voltage": 12.6,
"external_power": 1
}
},
"meta": {}
}
Device Position
Last known GPS position with full telemetry — coordinates, speed, ignition, sensors, and signal data.
/apidev/v1/fleet/devices/{id}/positionPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Device unique identifier |
Response Fields
| Field | Type | Description |
|---|---|---|
device_id | string | Device identifier |
device_name | string | null | Device display name |
latitude | number | Latitude coordinate |
longitude | number | Longitude coordinate |
speed | number | Speed in km/h |
heading | number | Heading in degrees (0–360) |
datetime | string | Timestamp of the position report |
last_signal_at | string | Timestamp of last signal received |
ignition_on_at | string | null | Timestamp when ignition was last turned on |
ignition_off_at | string | null | Timestamp when ignition was last turned off |
address | string | null | Reverse geocoded address |
odometer | number | null | Odometer reading (km) |
horometer | number | null | Hour meter reading (hours) |
satellites | number | null | GPS satellites in view |
battery_voltage | number | null | Battery voltage |
external_power | number | null | External power status |
Unlike Device Detail which nests GPS data under last_position, this endpoint returns position fields at the root level alongside device_id and device_name.
Code Example
- cURL
- JavaScript
- Python
curl -s "https://$TENANT/apidev/v1/fleet/devices/104820579301/position" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT"
const response = await fetch(
`https://${TENANT}/apidev/v1/fleet/devices/104820579301/position`,
{ headers }
);
const { data } = await response.json();
console.log(`${data.device_name}: ${data.latitude}, ${data.longitude} @ ${data.speed} km/h`);
response = requests.get(
f"https://{TENANT}/apidev/v1/fleet/devices/104820579301/position",
headers=headers,
)
pos = response.json()["data"]
print(f"{pos['device_name']}: {pos['latitude']}, {pos['longitude']} @ {pos['speed']} km/h")
Example Response
{
"success": true,
"data": {
"device_id": "104820579301",
"device_name": "Movil 10",
"latitude": -34.9011,
"longitude": -56.1645,
"speed": 62.5,
"heading": 270,
"datetime": "2026-04-04T14:45:12",
"last_signal_at": "2026-04-04T14:45:12",
"ignition_on_at": "2026-04-04T07:15:00",
"ignition_off_at": null,
"address": "Ruta 1 km 23, San Jose",
"odometer": 84523.7,
"horometer": 3210.5,
"satellites": 12,
"battery_voltage": 12.6,
"external_power": 1
},
"meta": {}
}
Position Fields
Reference for the position/telemetry fields used across Device Detail (last_position object) and Device Position (root level):
| Field | Type | In List | In Detail | In Position | Description |
|---|---|---|---|---|---|
latitude | number | ✓ | ✓ | ✓ | Latitude coordinate |
longitude | number | ✓ | ✓ | ✓ | Longitude coordinate |
speed | number | ✓ | ✓ | ✓ | Speed in km/h |
heading | number | ✓ | ✓ | ✓ | Heading 0–360° |
datetime | string | ✓ | ✓ | ✓ | Position timestamp |
last_signal_at | string | ✓ | ✓ | ✓ | Last signal timestamp |
ignition_on_at | string | null | ✓ | ✓ | ✓ | Ignition on timestamp |
ignition_off_at | string | null | ✓ | ✓ | ✓ | Ignition off timestamp |
address | string | null | ✓ | ✓ | ✓ | Reverse geocoded address |
odometer | number | null | ✓ | ✓ | ✓ | Odometer (km) |
horometer | number | null | ✓ | ✓ | ✓ | Hour meter (hours) |
satellites | number | null | — | ✓ | ✓ | GPS satellites |
battery_voltage | number | null | — | ✓ | ✓ | Battery voltage |
external_power | number | null | — | ✓ | ✓ | External power |
device_id | string | — | — | ✓ | Device ID (position only) |
device_name | string | null | — | — | ✓ | Device name (position only) |
All timestamps are returned without timezone (e.g., "2026-04-04T14:32:00"). The value represents the company's configured timezone. Do not append Z or apply UTC conversion — display as-is.
Update Device
Update a device's configuration. Only send the fields you want to change — omitted fields keep their current value. Send null to clear a nullable field.
/apidev/v1/fleet/devices/{id}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Device unique identifier |
Request Body
All fields are optional — only include those you want to modify. See Partial Updates for the general pattern.
| Field | Type | Max Length | Description |
|---|---|---|---|
name | string | 200 | Device display name |
alias | string | 200 | Short alias |
status | string | 10 | Device status (e.g., "A", "I") |
license_plate | string | 20 | Vehicle license plate (stored uppercase) |
brand | string | 100 | Vehicle brand |
model | string | 100 | Vehicle model |
year | integer | — | Vehicle model year |
max_speed | number | — | Maximum speed limit (km/h) |
tank_capacity | number | — | Fuel tank capacity in liters |
device_type_id | string | 40 | Device type identifier |
provider_id | string | 40 | Provider identifier |
country_id | string | 40 | Country identifier |
department_id | string | 40 | Department identifier |
gmt_offset | number | — | GMT timezone offset |
imei | string | 50 | Primary IMEI number |
imei2 | string | 50 | Secondary IMEI number |
external_id | string | 100 | External system identifier |
phone | string | 50 | SIM card phone number |
image_url | string | 500 | URL to the device/vehicle image |
notes | string | 2000 | Free-text notes |
temp_low | number | — | Low temperature alarm threshold |
temp_high | number | — | High temperature alarm threshold |
temp_sensor_1 | boolean | — | Enable temperature sensor 1 |
temp_sensor_2 | boolean | — | Enable temperature sensor 2 |
cut_oil | boolean | — | Fuel cut feature enabled |
virtual_odometer | boolean | — | Virtual odometer enabled |
Code Example
- cURL
- JavaScript
- Python
curl -s -X PUT "https://$TENANT/apidev/v1/fleet/devices/104820579301" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT" \
-H "Content-Type: application/json" \
-d '{
"license_plate": "ABC999",
"max_speed": 120,
"notes": "Updated route assignment"
}'
const response = await fetch(
`https://${TENANT}/apidev/v1/fleet/devices/104820579301`,
{
method: "PUT",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
license_plate: "ABC999",
max_speed: 120,
notes: "Updated route assignment",
}),
}
);
const { data } = await response.json();
console.log(`Updated fields: ${data.updated_fields.join(", ")}`);
response = requests.put(
f"https://{TENANT}/apidev/v1/fleet/devices/104820579301",
headers={**headers, "Content-Type": "application/json"},
json={
"license_plate": "ABC999",
"max_speed": 120,
"notes": "Updated route assignment",
},
)
print(response.json()["data"]["updated_fields"])
Example Response
{
"success": true,
"data": {
"id": "104820579301",
"updated_fields": ["license_plate", "max_speed", "notes"]
},
"meta": {}
}
Errors
All endpoints on this page may return these errors. See Error Handling for the full reference.
| Code | HTTP | Applies to | Description |
|---|---|---|---|
BAD_REQUEST | 400 | All | Missing required headers |
VALIDATION_ERROR | 400 | List, Update | Invalid query params or body fields (e.g., limit > 100, max_speed negative) |
UNAUTHORIZED | 401 | All | Invalid or expired JWT / API Key |
FORBIDDEN | 403 | All | User lacks APICLI_FLEET_DEVICES_READ or APICLI_FLEET_DEVICES_WRITE |
NOT_FOUND | 404 | Detail, Position, Update | Device ID doesn't exist or doesn't belong to your tenant |
RATE_LIMITED | 429 | All | Exceeded 30 req/min |
Related
- Drivers API — Manage drivers assigned to devices
- Telemetry — Ingest GPS positions from devices
- Pagination — Standard pagination parameters
- Partial Updates — How PUT endpoints work