Skip to content

Device Management

Overview

The Device APIs operate in two scopes (see the Field Reference for identifier definitions):

  1. Organization-wide device list at /api/v2/devices/, used to read every device under the active organization regardless of project.
  2. Project-scoped device management at /api/v2/projects/{project_id}/devices/, used for CRUD actions, data ingestion, and control commands for devices bound to a given project.

Devices are provisioned by hardware manufacturing flows and can only join an organization via the bind endpoint. Ad-hoc creation is not supported.

Endpoint Summary

ScopeMethodPathPurposeNotes
OrganizationGET/api/v2/devices/List all devices visible to the current tokenSee Organization-wide Device List.
ProjectGET/api/v2/projects/{project_id}/devices/List devices inside a project, supports search/filterSee List Devices in Project.
ProjectGET/api/v2/projects/{project_id}/devices/{device_pk}/Retrieve device detailsSee Get Device Details.
ProjectPUT/PATCH/api/v2/projects/{project_id}/devices/{device_pk}/Update metadata (info, allow, project)See Update Device.
ProjectPOST/api/v2/projects/{project_id}/devices/bind/Bind an existing device (by device_id + safe_code) to the projectSee Bind Device.
ProjectPOST/api/v2/projects/{project_id}/devices/{device_pk}/unbind/Remove project bindingSee Unbind Device.
ProjectGET/POST/api/v2/projects/{project_id}/devices/{device_pk}/data/Read cached telemetry or push uplink payloadsSee Device Data Endpoints.
ProjectPOST/api/v2/projects/{project_id}/devices/{device_pk}/reboot/Send reboot command (if supported)See Device Control.
ProjectPOST/api/v2/projects/{project_id}/devices/{device_pk}/set-serial/Configure serial parametersSee Device Control.
ProjectPOST/api/v2/projects/{project_id}/devices/{device_pk}/set-tcp/Configure remote TCP endpointSee Device Control.
ProjectPOST/api/v2/projects/{project_id}/devices/{device_pk}/export-factors/Download factor configuration JSONSee Export/Import Factors.
ProjectPOST/api/v2/projects/{project_id}/devices/{device_pk}/import-factors/Upload factor configuration JSONSee Export/Import Factors.
ProjectPOST/api/v2/projects/{project_id}/devices/{device_pk}/add-module/Import factor templates from a moduleSee Add Module.
ProjectPOST/api/v2/projects/{project_id}/devices/{device_pk}/set-project/Move device to another project within the same orgSee Move Device to Another Project.

Organization-wide Device List

Request

http
GET /api/v2/devices/
Authorization: Bearer <token>
QueryTypeDescription
searchstringFilter by device_id, device_name, or info (case-insensitive)
project_idstringRestrict results to a specific project

Response

Returns a flat list (no pagination) of devices including device_id, device_name, info, allow, bind_time, create_time, and project reference.

Project-scoped Operations

All endpoints below use the base path /api/v2/projects/{project_id}/devices/. Replace {project_id} with the public project identifier and {device_pk} with the internal device primary key.

List Devices in Project

http
GET /api/v2/projects/{project_id}/devices/
Authorization: Bearer <token>

Supports search query parameter identical to the organization endpoint. Responses are paginated (default page size depends on DRF settings) and cacheable for 60 seconds.

Get Device Details

http
GET /api/v2/projects/{project_id}/devices/{device_pk}/
Authorization: Bearer <token>

Returns the payload including derived fields:

json
{
    "id": 42,
    "device_id": "868686000123456",
    "device_name": "Cold-room node #1",
    "info": "Walk-in freezer",
    "allow": true,
    "bind_time": "2024-01-08T10:00:00Z",
    "has_thresholds": true,
    "project": {
        "project_id": "cold-chain-east",
        "name": "Cold Chain East"
    }
}

Update Device Metadata

http
PATCH /api/v2/projects/{project_id}/devices/{device_pk}/
Authorization: Bearer <token>
Content-Type: application/json

{
    "info": "Greenhouse #3 gateway",
    "allow": true
}
FieldTypeNotes
infostringUpdates operator-facing description
allowbooleanWhen false, the device cannot relay data
projectPKOnly via set-project action; direct update is blocked

Bind Device

Devices ship with a safe_code. Bind by referencing the hardware device_id and matching safe_code.

http
POST /api/v2/projects/{project_id}/devices/bind/
Authorization: Bearer <token>
Content-Type: application/json

{
    "device_id": "868686000123456",
    "safe_code": "8K2P"
}

Successful responses return the newly bound device record. Errors:

StatusMessage
404Device not found or safe code mismatch
400Device already bound to another project
404Project not found (invalid project_id)

Unbind Device

http
POST /api/v2/projects/{project_id}/devices/{device_pk}/unbind/
Authorization: Bearer <token>

Returns 204 No Content. After unbinding, the device becomes unassigned and can be bound to a different project.

Telemetry Endpoint

/data/ is dual-purpose:

  • GET: fetches cached data for the device and its sub-devices. Response is an array of simple objects such as { "agri_id": "d-1000-abcd-01", "temp": 24.1, "t": 1708070400 }. Data is cached for ~120 seconds.
  • POST: accepts a list of data points from device gateways. The API enriches each item with the_type, project_id, org_id, ensures timestamps exist, and pushes the payload into the SQS ingestion pipeline. Payload example:
json
[
    { "agri_id": "d-1000-abcd-01", "value": 24.3, "t": 1708070400 },
    { "agri_id": "d-1000-abcd-02", "value": 68.2 }
]

Control & Configuration Actions

ActionPathBodyNotes
RebootPOST /reboot/{}Requires device online and SUPPORTS_REBOOT flag
Set SerialPOST /set-serial/{ "baud_rate": 9600, "data_bits": 8, "stop_bits": 1, "parity": "NONE" }Validates parameters, then emits NAT@AT+UART1 command followed by reboot
Set TCPPOST /set-tcp/{ "host": "iot.yanjiiot.com", "port": 1883 }Sends NAT@AT+SOCK1A command
Export FactorsPOST /export-factors/nullReturns downloadable JSON with factor definitions
Import FactorsPOST /import-factors/multipart form with fileAccepts exported JSON; optional clear_existing flag
Add ModulePOST /add-module/{ "module_id": 5, "slave_id": 1 }Loads module templates into factors
Set ProjectPOST /set-project/{ "project_id": "new-project" }Moves device to another project within same organization

Each action returns either a status message or the serialized device. Failures provide standard error envelopes.

Example: List Devices via Python

python
import requests

API_BASE = "https://dl.holdingbyte.com/api/v2"
TOKEN = "your_access_token"

def list_project_devices(project_id, search=None):
    headers = {"Authorization": f"Bearer {TOKEN}"}
    params = {"search": search} if search else None
    url = f"{API_BASE}/projects/{project_id}/devices/"
    response = requests.get(url, headers=headers, params=params)
    response.raise_for_status()
    return response.json()

devices = list_project_devices("greenhouse-alpha", search="gateway")
print(devices)

Error Codes

StatusCodeDescription
401UNAUTHORIZEDMissing or invalid token
403FORBIDDENCaller lacks manager role or token not scoped to project
404DEVICE_NOT_FOUNDDevice PK not in project or project does not exist
409DEVICE_ALREADY_BOUNDBind attempted on already assigned device
422INVALID_COMMANDControl parameters fail validation
500DEVICE_COMMAND_FAILEDDownstream failure while issuing command

Operational Notes

  1. Caching: GET list/detail responses are cached. Use POST actions to invalidate state or wait for TTL (60–300 seconds).
  2. Data Integrity: When POSTing telemetry, ensure agri_id values start with the parent device agri_id prefix; mismatches are dropped silently.
  3. Safe Codes: Each hardware unit has a four-character safe code printed on the label. Share it securely; anyone with device_id + safe_code can bind the device.
  4. Online Checks: Control actions verify device connectivity via connect_time and may return 503 Service Unavailable if the device is offline.
  5. Project Move: set-project requires both projects to belong to the same organization. Moving a device clears cached listings for affected projects.