Devices
Onboard Band/Bag Tags hardware (trackers/scanners). Register devices (admin, public self-registration, and approval), look up a device by serial number, update device details, and read live telemetry — heartbeat-derived status, status history and data-usage.
GET List Devices {{url}}/devices ▸
Retrieve a paginated list of hardware devices (trackers, scanners, gateways) registered with TerraGo.
Query Parameters
- per_page (
integer, optional, default 10, max 20) - status (
string, optional):ONLINE,OFFLINE,LOWBATTERY,PENDINGAPPROVAL,OTHER, orN/A. - assigned (
integer, optional):1for devices assigned to a school/staff,0for unassigned. - supervisor_id (
stringUUID, optional): Filter by Administrative Staff (school). - search (
string, optional): Matches name, description, or serial number.
Response
Paginated list of devices (data) with meta; each includes live-derived status, battery, NFC/location flags, signal and data usage.
{
"status": "ONLINE", //only use: ONLINE, OFFLINE, LOW_BATTERY, OTHER, N/A
"search": "",
"supervisor_id": "68b86410-e6e8-4b5f-9a3d-8265a7773c0e",
"per_page": 10,
"page": 1
}{
"data": [
{
"id": "e91c072b-508c-448d-a368-f22c34434742",
"name": "name",
"description": "description",
"sim_phone_number": "+254725544432",
"serial_number": "serial_number",
"waas_zone_uuid": "ada52fc6-d481-48d9-82b3-fddb07d5d44f",
"waas_zone_name": "Terra HQ",
"est_data_usage": "2000",
"type": "Scanner",
"administrative_staff": {
"id": "68b86410-e6e8-4b5f-9a3d-8265a7773c0e",
"first_name": "Jane",
"last_name": "Otieno"
},
"status": "Online",
"last_activity": "2025-12-27 14:10:56",
"battery_level": 100,
"metadata": null
}
],
"links": {
"first": "http://localhost:8001/api/devices?page=1",
"last": "http://localhost:8001/api/devices?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"page": null,
"active": false
},
{
"url": "http://localhost:8001/api/devices?page=1",
"label": "1",
"page": 1,
"active": true
},
{
"url": null,
"label": "Next »",
"page": null,
"active": false
}
],
"path": "http://localhost:8001/api/devices",
"per_page": 15,
"to": 1,
"total": 1
},
"status": 200,
"message": "Devices Retrieved Successfully"
}
GET Get Device by Serial Number {{url}}/devices/get-by-serial/serial_number ▸
Look up a device by its physical serial number rather than its internal UUID — handy when scanning/typing a label off the hardware itself.
Path Parameters
- id (
string, required): The device'sserial_number(not its UUID, despite the parameter name).
Response
The single device (data).
{
"status": 200,
"data": {
"id": "1aa126a1-f056-4b4e-bd59-9b821ff50bb9",
"name": "name",
"description": "description",
"sim_phone_number": null,
"serial_number": "serial_number",
"waas_zone_uuid": null,
"waas_zone_name": null,
"est_data_usage": null,
"type": "Scanner",
"administrative_staff": {
"id": "46b0a803-39c8-4113-8b29-8ef30438c5bd",
"first_name": "PM",
"last_name": "School"
},
"status": "Pending Approval",
"last_activity": "2026-01-27 09:57:54",
"battery_level": 100,
"metadata": null
},
"message": "Device retrieved successfully"
}
PUT Update Device {{url}}/devices/update/e91c072b-508c-448d-a368-f22c34434742 ▸
Update a device's configuration. Changes are pushed to TerraGo's zone/location and tag registry in the same request (transactional — if the registry call fails, nothing is saved locally).
Path Parameters
- id (
stringUUID, required): Device UUID.
Request Body
- name (
string, required) - description (
string, required) - serial_number (
string, required, must be unique) - type (
string, required):TRACKER,SCANNER,GATEWAY,OTHER, orN/A. - estdatausage (
integer, required, min 1): Estimated monthly data usage. - imei (
string, optional, max 32) - simphonenumber (
string, optional) - waaszoneuuid / waaszonename (
string, optional): Reassign to a different vehicle/zone/location. - status (
string, optional):ONLINE,OFFLINE,LOWBATTERY,PENDINGAPPROVAL,OTHER, orN/A. - battery_level (
integer, optional, 0–100, default 100) - administativestaffid (
stringUUID, optional): School the device belongs to; resolved from the authenticated user if omitted.
Notes
- If
batterylevelis 25 or below,statusis forced toLOWBATTERYregardless of what's passed in. administativestaffidmust be resolvable (from the request or from your own account) or this returns a422.
{
"name": "name",
"description": "description",
"serial_number": "serial_number",
"administative_staff_id":"68b86410-e6e8-4b5f-9a3d-8265a7773c0e",
"sim_phone_number": "+254725544432",
"waas_zone_uuid":"ada52fc6-d481-48d9-82b3-fddb07d5d44f",
"waas_zone_name":"Terra HQ",
"est_data_usage":"2000", //In MBs
"type": "SCANNER", //only use: SCANNER, GATEWAY, TRACKER, OTHER, N/A
"battery_level":"100",
"status": "ONLINE" //only use: ONLINE, OFFLINE, LOW_BATTERY, OTHER, N/A
}{
"status": 200,
"data": {
"id": "e91c072b-508c-448d-a368-f22c34434742",
"name": "name",
"description": "description",
"sim_phone_number": "+254725544432",
"serial_number": "serial_number",
"waas_zone_uuid": "ada52fc6-d481-48d9-82b3-fddb07d5d44f",
"waas_zone_name": "Terra HQ",
"est_data_usage": "2000",
"type": "Scanner",
"administrative_staff": {
"id": "68b86410-e6e8-4b5f-9a3d-8265a7773c0e",
"first_name": "Jane",
"last_name": "Otieno"
},
"status": "Online",
"last_activity": "2025-12-27 14:56:47",
"battery_level": "100",
"metadata": null
},
"message": "Device updated successfully"
}
POST Register Device (Admin) {{url}}/devices/add ▸
Register a new device directly (as an admin), immediately creating it in both TerraGo and TerraGo's zone/location and tag registry with ONLINE status. Compare to Request Registration, which is the self-service flow devices use before an admin approves them.
Request Body
Same fields as Update Device: name, description, serialnumber (required, unique), type (required), estdatausage (required), plus optional imei, simphonenumber, waaszoneuuid, waaszonename, status, batterylevel, administativestaffid.
Notes
- Also seeds an initial device-status-log entry so uptime tracking has a baseline from creation time.
Response
The created device (data).
{
"name": "name",
"description": "description",
"serial_number": "serial_number",
"administative_staff_id":"68b86410-e6e8-4b5f-9a3d-8265a7773c0e",
"sim_phone_number": "+254725544432",
"waas_zone_uuid":"ada52fc6-d481-48d9-82b3-fddb07d5d44f",
"waas_zone_name":"Terra HQ",
"est_data_usage":"2000", //In MBs
"type": "SCANNER" //only use: SCANNER, GATEWAY, TRACKER, OTHER, N/A
}{
"status": 200,
"data": {
"id": "e91c072b-508c-448d-a368-f22c34434742",
"name": "name",
"description": "description",
"sim_phone_number": "+254725544432",
"serial_number": "serial_number",
"waas_zone_uuid": "ada52fc6-d481-48d9-82b3-fddb07d5d44f",
"waas_zone_name": "Terra HQ",
"est_data_usage": "2000",
"type": "Scanner",
"administrative_staff": {
"id": "68b86410-e6e8-4b5f-9a3d-8265a7773c0e",
"first_name": "Jane",
"last_name": "Otieno"
},
"status": "Online",
"last_activity": "2025-12-27 14:10:56",
"battery_level": 100,
"metadata": null
},
"message": "Device registered successfully"
}
POST Self-Register Device (Public) {{url}}/devices/request-registration ▸
Public, unauthenticated endpoint a device (or field technician) calls to request that a device be added to the system. Creates the device with PENDING_APPROVAL status and does not sync to the registry yet — an admin must call Approve Registration to finish onboarding it.
Request Body
- name (
string, required) - description (
string, required) - serial_number (
string, required, must be globally unique)
Notes
- No bearer token required — this is meant to be callable from the device itself before it has any credentials.
Response
Confirmation the registration request was submitted (data) — the device is pending admin approval.
{
"name": "name", // Human-readable name / label
"description": "description", // Optional free-text description
"serial_number": "serial_number" // Device serial number
}{
"status": 200,
"data": {
"id": "1aa126a1-f056-4b4e-bd59-9b821ff50bb9",
"name": "name",
"description": "description",
"sim_phone_number": null,
"serial_number": "serial_number",
"waas_zone_uuid": null,
"waas_zone_name": null,
"est_data_usage": null,
"type": "Scanner",
"administrative_staff": {
"id": "46b0a803-39c8-4113-8b29-8ef30438c5bd",
"first_name": "PM",
"last_name": "School"
},
"status": "Pending Approval",
"last_activity": "2026-02-27 10:30:12",
"battery_level": null,
"metadata": null
},
"message": "Device registered successfully"
}
POST Approve Device Registration {{url}}/devices/approve/1aa126a1-f056-4b4e-bd59-9b821ff50bb9 ▸
Admin approval step that completes onboarding for a device previously created via Request Registration: fills in the remaining details, syncs it to the registry, and moves it out of PENDING_APPROVAL.
Path Parameters
- id (
stringUUID, required): Device UUID (the one created by the self-registration call).
Request Body
Same fields as Update Device — administativestaffid is effectively required here since it determines which school the device is registered to in the registry.
Response
The approved/activated device (data).
{
"name": "name",
"description": "description",
"serial_number": "serial_number",
"administative_staff_id":"46b0a803-39c8-4113-8b29-8ef30438c5bd",
"sim_phone_number": "+254725544432",
"waas_zone_uuid":"ada52fc6-d481-48d9-82b3-fddb07d5d44f",
"waas_zone_name":"Terra HQ",
"est_data_usage":"2000", //In MBs
"type": "SCANNER" //only use: SCANNER, GATEWAY, TRACKER, OTHER, N/A
}{
"status": 200,
"data": {
"id": "38de6cc4-9043-454b-b3f2-ac67b591b09e",
"name": "name",
"description": "description",
"sim_phone_number": "+254725544432",
"serial_number": "serial_number",
"waas_zone_uuid": "ada52fc6-d481-48d9-82b3-fddb07d5d44f",
"waas_zone_name": "Terra HQ",
"est_data_usage": "2000",
"type": "Scanner",
"administrative_staff": {
"id": "46b0a803-39c8-4113-8b29-8ef30438c5bd",
"first_name": "PM",
"last_name": "School"
},
"status": "Low Battery",
"last_activity": "2026-02-27 10:52:15",
"battery_level": 100,
"metadata": null
},
"message": "Device registered successfully"
}
GET Device Status History {{url}}/devices/4e1cee0f-3c30-4d2b-8b99-36880590613b/status-history?from=2026-06-14&to=2026-07-13 ▸
Online/offline history for a device over a window (derived by diffing the append-only status log; per-heartbeat sample rows are excluded). Powers the Device Usage timeline + uptime stats.
Path Parameters
- id (
stringUUID, required): the device UUID.
Query Parameters
- from / to (
date, optional,YYYY-MM-DD): the window (defaults to the last ~7 days).fromis start-of-day,toend-of-day.
Response
data: from, to, uptimepercent, totaloutages, longestoutageseconds, and timeline[] (each {status, source, recorded_at}).
Requires a bearer token (auth:api).
{
"status": 200,
"data": {
"from": "2026-06-14",
"to": "2026-07-13",
"uptime_percent": 98.7,
"total_outages": 2,
"longest_outage_seconds": 5400,
"timeline": [
{ "status": "Online", "source": "heartbeat", "recorded_at": "2026-06-14" },
{ "status": "Offline", "source": "heartbeat", "recorded_at": "2026-06-20" }
]
},
"message": "Device status history retrieved"
}
GET Device Data Usage {{url}}/devices/4e1cee0f-3c30-4d2b-8b99-36880590613b/usage?from=2026-06-14&to=2026-07-13 ▸
Per-day data usage (and average battery) for a device over a window, for the usage chart. Reads the per-heartbeat sample telemetry rows: each day is the SUM of that day's datausedmb (0 when none).
Path Parameters
- id (
stringUUID, required): the device UUID.
Query Parameters
- from / to (
date, optional,YYYY-MM-DD): the window (defaults to the last ~7 days).
Response
data: from, to, totalusedmb, and series[] (each {date, usedmb, avgbattery}).
Requires a bearer token (auth:api).
{
"status": 200,
"data": {
"from": "2026-06-14",
"to": "2026-07-13",
"total_used_mb": 128,
"series": [
{ "date": "2026-06-14", "used_mb": 12, "avg_battery": 86 },
{ "date": "2026-06-15", "used_mb": 0, "avg_battery": 90 }
]
},
"message": "Device usage retrieved"
}
GET Device Status Logs (Cursor Paginated) {{url}}/devices/4e1cee0f-3c30-4d2b-8b99-36880590613b/status-logs?from=2026-06-14&to=2026-07-13&per_page=15 ▸
The scrollable status-change log for a device (status transitions only — per-heartbeat sample rows are excluded), newest first, cursor-paginated. The aggregate uptime/outage numbers live in Device Status History; this is just the raw log feed.
Path Parameters
- id (
stringUUID, required): the device UUID.
Query Parameters
- from / to (
date, optional,YYYY-MM-DD): the window. - per_page (
integer, optional, default 15, max 50). - cursor (opaque, optional): pass
meta.nextcursor/meta.prevcursorfrom a previous response to page.
Response
data.data[] (each {status, batterylevel, source, recordedat}) + data.meta (perpage, nextcursor, prev_cursor).
Requires a bearer token (auth:api).
{
"status": 200,
"data": {
"data": [
{ "status": "Offline", "battery_level": 18, "source": "heartbeat", "recorded_at": "2026-07-12" },
{ "status": "Online", "battery_level": 74, "source": "heartbeat", "recorded_at": "2026-07-11" }
],
"meta": {
"per_page": 15,
"next_cursor": "eyJyZWNvcmRlZF9hdCI6...",
"prev_cursor": null
}
},
"message": "Device status logs retrieved"
}