For frontend developers: All responses below are representative dummy values. Use them directly to build and test UI components. The backend will return the same shape when implemented.
Authentication
POST
/auth/register
Register a new user account
No auth required
Request body
Response
Errors
FieldTypeRequiredDescription
display_namestringrequiredFull name shown in the UI
emailstringrequiredUnique email address
passwordstringrequiredMin 8 characters

Example request body
"display_name": "Arjun Mehta",
"email": "arjun@example.com",
"password": "securePass123"
201 Created
{
  "success": true,
  "data": {
    "user": {
      "id": "usr_01HXKJ2P3M4N5Q6R7S8T9V0W",
      "display_name": "Arjun Mehta",
      "email": "arjun@example.com",
      "is_verified": false,
      "created_at": "2025-01-15T09:23:45Z"
    },
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "rt_8fKj2mP9xZqL3nR7sT...",
    "expires_in": 3600
  }
}
StatusCodeReason
400VALIDATION_ERRORMissing or invalid fields
409EMAIL_ALREADY_EXISTSEmail is already registered
POST
/auth/login
Authenticate and receive access + refresh tokens
No auth required
Request body
Response
Errors
FieldTypeRequiredDescription
emailstringrequiredRegistered email
passwordstringrequiredAccount password
200 OK
{
  "success": true,
  "data": {
    "user": {
      "id": "usr_01HXKJ2P3M4N5Q6R7S8T9V0W",
      "display_name": "Arjun Mehta",
      "email": "arjun@example.com",
      "is_verified": true,
      "created_at": "2025-01-15T09:23:45Z"
    },
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "rt_8fKj2mP9xZqL3nR7sT...",
    "expires_in": 3600
  }
}
StatusCodeReason
401INVALID_CREDENTIALSWrong email or password
403EMAIL_NOT_VERIFIEDAccount not yet verified
GET
/auth/me
Get the authenticated user's profile
Auth required
Response
200 OK
{
  "success": true,
  "data": {
    "id": "usr_01HXKJ2P3M4N5Q6R7S8T9V0W",
    "display_name": "Arjun Mehta",
    "email": "arjun@example.com",
    "is_verified": true,
    "created_at": "2025-01-15T09:23:45Z",
    "updated_at": "2025-03-10T14:05:00Z"
  }
}
POST
/auth/refresh
Exchange a refresh token for a new access token
No auth required
Request body
Response
FieldTypeRequiredDescription
refresh_tokenstringrequiredRefresh token from login/register
200 OK
{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_in": 3600
  }
}
POST
/auth/logout
Invalidate the current refresh token
Auth required
Request body
Response
FieldTypeRequiredDescription
refresh_tokenstringrequiredToken to revoke
200 OK
{
  "success": true,
  "message": "Logged out successfully"
}
Projects
GET
/projects
List all projects owned by the authenticated user
Auth required
Response
200 OK
{
  "success": true,
  "data": [
    {
      "id": "prj_01HXKM3A2B4C5D6E7F8G9H0J",
      "name": "Smart Greenhouse",
      "description": "Climate and irrigation monitoring",
      "device_count": 4,
      "created_at": "2025-01-20T08:00:00Z",
      "updated_at": "2025-03-01T12:30:00Z"
    },
    {
      "id": "prj_02JYKN4B3C5D6E7F8G9H1K2L",
      "name": "Factory Floor Monitor",
      "description": "Temperature and vibration on CNC machines",
      "device_count": 12,
      "created_at": "2025-02-05T10:15:00Z",
      "updated_at": "2025-03-15T09:00:00Z"
    }
  ],
  "meta": { "total": 2 }
}
POST
/projects
Create a new project
Auth required
Request body
Response
FieldTypeRequiredDescription
namestringrequiredProject name (max 80 chars)
descriptionstringoptionalShort description (max 500 chars)
201 Created
{
  "success": true,
  "data": {
    "id": "prj_03KZLN5C4D6E7F8G9H0J1K3M",
    "name": "Home Automation",
    "description": "Smart home sensors and controls",
    "device_count": 0,
    "created_at": "2025-04-01T11:00:00Z",
    "updated_at": "2025-04-01T11:00:00Z"
  }
}
GET
/projects/:projectId
Get a single project by ID
Auth required
Response
Errors
200 OK
{
  "success": true,
  "data": {
    "id": "prj_01HXKM3A2B4C5D6E7F8G9H0J",
    "name": "Smart Greenhouse",
    "description": "Climate and irrigation monitoring",
    "device_count": 4,
    "created_at": "2025-01-20T08:00:00Z",
    "updated_at": "2025-03-01T12:30:00Z"
  }
}
StatusCodeReason
404PROJECT_NOT_FOUNDNo project with that ID, or not owned by user
PUT
/projects/:projectId
Update project name or description
Auth required
Request body
Response
FieldTypeRequiredDescription
namestringoptionalNew project name
descriptionstringoptionalNew description
200 OK — returns updated project object (same shape as GET)
{ "success": true, "data": { /* updated project */ } }
DELETE
/projects/:projectId
Delete a project and all its devices (cascading)
Auth required
Response
200 OK
{ "success": true, "message": "Project deleted" }
Devices
GET
/projects/:projectId/devices
List all devices in a project
Auth required
Response
200 OK
{
  "success": true,
  "data": [
    {
      "id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
      "project_id": "prj_01HXKM3A2B4C5D6E7F8G9H0J",
      "name": "GH-Sensor-Node-01",
      "description": "North greenhouse bay sensors",
      "firmware_version": "1.4.2",
      "sensor_count": 3,
      "status": "online",
      "last_seen_at": "2025-04-30T18:55:00Z",
      "created_at": "2025-01-22T10:00:00Z"
    },
    {
      "id": "dev_02JYKP7E6F8G9H0J1K2L3M4N",
      "project_id": "prj_01HXKM3A2B4C5D6E7F8G9H0J",
      "name": "GH-Irrigation-Ctrl",
      "description": "Irrigation valve controller",
      "firmware_version": "2.0.0",
      "sensor_count": 1,
      "status": "offline",
      "last_seen_at": "2025-04-29T03:12:00Z",
      "created_at": "2025-01-25T14:00:00Z"
    }
  ],
  "meta": { "total": 2 }
}
POST
/projects/:projectId/devices
Register a new device under a project. Returns a one-time secret key for the physical device.
Auth required
Request body
Response
FieldTypeRequiredDescription
namestringrequiredUnique name within the project
descriptionstringoptionalHuman description of device's role
201 Created
The secret_key is only returned once at creation. Flash it to the physical device immediately — it cannot be retrieved again.
{
  "success": true,
  "data": {
    "id": "dev_03KZLQ8F7G9H0J1K2L3M4N5P",
    "project_id": "prj_01HXKM3A2B4C5D6E7F8G9H0J",
    "name": "GH-CO2-Sensor",
    "description": "CO2 level monitor",
    "secret_key": "sk_live_Xk9mP2nQ7rT4vW8yZ...",
    "firmware_version": null,
    "created_at": "2025-04-30T19:00:00Z"
  }
}
GET
/devices/:deviceId
Get a single device (includes live status)
Auth required
Response
200 OK
{
  "success": true,
  "data": {
    "id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
    "project_id": "prj_01HXKM3A2B4C5D6E7F8G9H0J",
    "name": "GH-Sensor-Node-01",
    "description": "North greenhouse bay sensors",
    "firmware_version": "1.4.2",
    "status": "online",
    "ip_address": "192.168.1.45",
    "last_seen_at": "2025-04-30T18:55:00Z",
    "sensor_count": 3,
    "created_at": "2025-01-22T10:00:00Z",
    "updated_at": "2025-03-10T08:00:00Z"
  }
}
PUT
/devices/:deviceId
Update device name or description
Auth required
Request body
Response
FieldTypeRequiredDescription
namestringoptionalNew device name
descriptionstringoptionalNew description
{ "success": true, "data": { /* updated device object */ } }
DELETE
/devices/:deviceId
Delete a device and all its sensors, variables, and telemetry
Auth required
Response
{ "success": true, "message": "Device deleted" }
GET
/devices/:deviceId/status
Get real-time online/offline status of a device
Auth required
Response
200 OK
{
  "success": true,
  "data": {
    "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
    "status": "online",
    "ip_address": "192.168.1.45",
    "last_seen_at": "2025-04-30T18:55:00Z",
    "updated_at": "2025-04-30T18:55:02Z"
  }
}
Sensors
GET
/devices/:deviceId/sensors
List all sensors attached to a device
Auth required
Response
200 OK
{
  "success": true,
  "data": [
    {
      "id": "sen_01HXKR9G8H0J1K2L3M4N5P6Q",
      "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
      "name": "DS18B20",
      "description": "Waterproof digital temperature sensor",
      "unit": "°C",
      "variable_count": 1,
      "created_at": "2025-01-23T11:00:00Z"
    },
    {
      "id": "sen_02JYKS0H9J1K2L3M4N5P6Q7R",
      "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
      "name": "SHT31",
      "description": "Temperature and humidity combo",
      "unit": null,
      "variable_count": 2,
      "created_at": "2025-01-23T11:05:00Z"
    }
  ],
  "meta": { "total": 2 }
}
POST
/devices/:deviceId/sensors
Add a sensor to a device
Auth required
Request body
Response
FieldTypeRequiredDescription
namestringrequiredSensor model or identifier name
descriptionstringoptionalHuman-readable description
unitstringoptionalPhysical unit e.g. °C, hPa, %
201 Created — returns created sensor object
{ "success": true, "data": { /* sensor object */ } }
GET
/sensors/:sensorId
Get a single sensor with its variables
Auth required
Response
200 OK
{
  "success": true,
  "data": {
    "id": "sen_02JYKS0H9J1K2L3M4N5P6Q7R",
    "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
    "name": "SHT31",
    "description": "Temperature and humidity combo",
    "unit": null,
    "variables": [
      { "id": "var_01...", "label": "temperature", "data_type": "float" },
      { "id": "var_02...", "label": "humidity", "data_type": "float" }
    ],
    "created_at": "2025-01-23T11:05:00Z"
  }
}
PUT
/sensors/:sensorId
Update sensor name, description, or unit
Auth required
Response
{ "success": true, "data": { /* updated sensor */ } }
DELETE
/sensors/:sensorId
Delete sensor and its variables (cascades telemetry)
Auth required
Response
{ "success": true, "message": "Sensor deleted" }
Variables
Data types: Variables support four types — float, integer, boolean, string. The label is used as the key in telemetry payloads from the device.
GET
/sensors/:sensorId/variables
List all variables defined on a sensor
Auth required
Response
200 OK
{
  "success": true,
  "data": [
    {
      "id": "var_01HXKT1J0K2L3M4N5P6Q7R8S",
      "sensor_id": "sen_02JYKS0H9J1K2L3M4N5P6Q7R",
      "label": "temperature",
      "data_type": "float",
      "latest_value": 24.7,
      "latest_at": "2025-04-30T18:54:30Z",
      "created_at": "2025-01-23T12:00:00Z"
    },
    {
      "id": "var_02JYKU2K1L3M4N5P6Q7R8S9T",
      "sensor_id": "sen_02JYKS0H9J1K2L3M4N5P6Q7R",
      "label": "humidity",
      "data_type": "float",
      "latest_value": 68.2,
      "latest_at": "2025-04-30T18:54:30Z",
      "created_at": "2025-01-23T12:00:00Z"
    }
  ]
}
POST
/sensors/:sensorId/variables
Define a new variable on a sensor
Auth required
Request body
Response
Errors
FieldTypeRequiredDescription
labelstringrequiredUnique label within the sensor e.g. temperature
data_typeenumrequiredfloat | integer | boolean | string
201 Created
{ "success": true, "data": { /* variable object */ } }
StatusCodeReason
409LABEL_ALREADY_EXISTSLabel already used on this sensor
400INVALID_DATA_TYPEdata_type must be one of the allowed enum values
GET
/variables/:variableId
Get a single variable
Auth required
Response
{ "success": true, "data": { /* variable object with latest_value */ } }
PUT
/variables/:variableId
Update variable label (data_type is immutable once telemetry exists)
Auth required
Response
{ "success": true, "data": { /* updated variable */ } }
DELETE
/variables/:variableId
Delete variable and all its telemetry history
Auth required
Response
{ "success": true, "message": "Variable deleted" }
Command Templates
GET
/devices/:deviceId/command-templates
List all command templates defined for a device
Auth required
Response
200 OK
{
  "success": true,
  "data": [
    {
      "id": "cmt_01HXKV3L2M4N5P6Q7R8S9T0V",
      "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
      "name": "changeLevel",
      "description": "Set irrigation valve level (0-100%)",
      "parameters": [
        {
          "id": "cmp_01HXKW4M3N5P6Q7R8S9T0V1W",
          "param_name": "level",
          "param_type": "integer",
          "param_order": 1,
          "default_value": "0",
          "is_required": true
        }
      ],
      "created_at": "2025-02-01T09:00:00Z"
    },
    {
      "id": "cmt_02JYKW4M3N5P6Q7R8S9T0V1W",
      "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
      "name": "reboot",
      "description": "Reboot the device firmware",
      "parameters": [],
      "created_at": "2025-02-01T09:05:00Z"
    }
  ]
}
POST
/devices/:deviceId/command-templates
Create a new command template with optional parameters
Auth required
Request body
Response
FieldTypeRequiredDescription
namestringrequiredCommand name e.g. changeLevel
descriptionstringoptionalWhat the command does
parametersarrayoptionalArray of parameter definitions (see below)
parameters[].param_namestringrequiredParameter name e.g. level
parameters[].param_typeenumrequiredinteger | float | string | boolean
parameters[].param_orderintegerrequiredDisplay order (1-based)
parameters[].default_valuestringoptionalDefault value as string
parameters[].is_requiredbooleanoptionalDefaults to true

Example — changeLevel(int level)
{
  "name": "changeLevel",
  "description": "Set irrigation valve level 0-100",
  "parameters": [
    {
      "param_name": "level",
      "param_type": "integer",
      "param_order": 1,
      "default_value": "0",
      "is_required": true
    }
  ]
}
201 Created — returns full template with parameters
{ "success": true, "data": { /* template object */ } }
GET
/command-templates/:templateId
Get a single command template with its parameters
Auth required
Response
{ "success": true, "data": { /* template + parameters array */ } }
PUT
/command-templates/:templateId
Update name, description, or replace parameters array
Auth required
Response
{ "success": true, "data": { /* updated template */ } }
DELETE
/command-templates/:templateId
Delete a command template (does not delete historic instances)
Auth required
Response
{ "success": true, "message": "Command template deleted" }
Command Dispatch
POST
/command-templates/:templateId/dispatch
Send a command to a device. Server validates ownership, argument types, and queues delivery. Returns a command instance to track status.
Auth required
Request body
Response
Errors
FieldTypeRequiredDescription
parametersobjectoptionalKey-value pairs matching parameter names defined in the template
ttl_secondsintegeroptionalCommand expires after this many seconds if not delivered. Default: 3600

Example — dispatch changeLevel(level=75)
{
  "parameters": {
    "level": 75
  },
  "ttl_seconds": 300
}
202 Accepted
{
  "success": true,
  "data": {
    "id": "cmi_01HXKX5N4P6Q7R8S9T0V1W2X",
    "template_id": "cmt_01HXKV3L2M4N5P6Q7R8S9T0V",
    "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
    "command_name": "changeLevel",
    "parameters": { "level": 75 },
    "status": "queued",
    "issued_by": "usr_01HXKJ2P3M4N5Q6R7S8T9V0W",
    "created_at": "2025-04-30T19:10:00Z",
    "queued_at": "2025-04-30T19:10:01Z",
    "sent_at": null,
    "executed_at": null,
    "expired_at": null,
    "failure_reason": null,
    "expires_at": "2025-04-30T19:15:00Z"
  }
}
StatusCodeReason
403NOT_DEVICE_OWNERAuthenticated user does not own this device
400MISSING_REQUIRED_PARAMA required parameter was not provided
400INVALID_PARAM_TYPEParameter value does not match declared type
422DEVICE_QUEUE_FULLToo many pending commands for this device
GET
/command-instances/:instanceId
Poll the current status of a dispatched command
Auth required
Response
200 OK — example after device executes successfully
{
  "success": true,
  "data": {
    "id": "cmi_01HXKX5N4P6Q7R8S9T0V1W2X",
    "command_name": "changeLevel",
    "parameters": { "level": 75 },
    "status": "success",
    "created_at": "2025-04-30T19:10:00Z",
    "queued_at": "2025-04-30T19:10:01Z",
    "sent_at": "2025-04-30T19:10:03Z",
    "executed_at": "2025-04-30T19:10:05Z",
    "expired_at": null,
    "failure_reason": null
  }
}
GET
/devices/:deviceId/command-history
Paginated history of all command instances sent to a device
Auth required
Query params
Response
ParamTypeDefaultDescription
pageinteger1Page number
limitinteger20Items per page (max 100)
statusstringFilter by status e.g. failed
200 OK
{
  "success": true,
  "data": [
    { "id": "cmi_01...", "command_name": "changeLevel", "status": "success", "created_at": "2025-04-30T19:10:00Z" },
    { "id": "cmi_02...", "command_name": "reboot", "status": "expired", "created_at": "2025-04-29T08:00:00Z" }
  ],
  "meta": { "total": 24, "page": 1, "limit": 20, "total_pages": 2 }
}
Telemetry
GET
/variables/:variableId/telemetry
Fetch time-series readings for a variable within a time range
Auth required
Query params
Response
ParamTypeRequiredDescription
fromISO 8601requiredStart of time range e.g. 2025-04-30T00:00:00Z
toISO 8601requiredEnd of time range
limitintegerMax datapoints (default 1000, max 5000)
200 OK
{
  "success": true,
  "data": {
    "variable_id": "var_01HXKT1J0K2L3M4N5P6Q7R8S",
    "label": "temperature",
    "data_type": "float",
    "unit": "°C",
    "readings": [
      { "value": 24.3, "recorded_at": "2025-04-30T18:00:00Z" },
      { "value": 24.5, "recorded_at": "2025-04-30T18:05:00Z" },
      { "value": 24.7, "recorded_at": "2025-04-30T18:10:00Z" },
      { "value": 25.1, "recorded_at": "2025-04-30T18:15:00Z" }
    ],
    "meta": {
      "count": 4,
      "from": "2025-04-30T18:00:00Z",
      "to": "2025-04-30T18:15:00Z"
    }
  }
}
GET
/devices/:deviceId/telemetry/latest
Get the single most recent reading for every variable on a device (for dashboard snapshot)
Auth required
Response
200 OK
{
  "success": true,
  "data": [
    {
      "variable_id": "var_01HXKT1J0K2L3M4N5P6Q7R8S",
      "sensor_name": "SHT31",
      "label": "temperature",
      "data_type": "float",
      "value": 24.7,
      "recorded_at": "2025-04-30T18:54:30Z"
    },
    {
      "variable_id": "var_02JYKU2K1L3M4N5P6Q7R8S9T",
      "sensor_name": "SHT31",
      "label": "humidity",
      "data_type": "float",
      "value": 68.2,
      "recorded_at": "2025-04-30T18:54:30Z"
    },
    {
      "variable_id": "var_03KZLV3L2M4N5P6Q7R8S9T0V",
      "sensor_name": "DS18B20",
      "label": "soil_temp",
      "data_type": "float",
      "value": 19.1,
      "recorded_at": "2025-04-30T18:54:28Z"
    }
  ]
}
GET
/variables/:variableId/telemetry/aggregate
Get aggregated stats (min, max, avg, count) for a variable over a time window
Auth required
Query params
Response
ParamTypeRequiredDescription
fromISO 8601requiredStart of window
toISO 8601requiredEnd of window
intervalstringoptional1m | 5m | 1h | 1d — bucketing interval
200 OK
{
  "success": true,
  "data": {
    "variable_id": "var_01HXKT1J0K2L3M4N5P6Q7R8S",
    "label": "temperature",
    "interval": "1h",
    "buckets": [
      { "time": "2025-04-30T16:00:00Z", "min": 23.1, "max": 24.9, "avg": 24.0, "count": 12 },
      { "time": "2025-04-30T17:00:00Z", "min": 23.8, "max": 25.4, "avg": 24.5, "count": 12 },
      { "time": "2025-04-30T18:00:00Z", "min": 24.3, "max": 25.1, "avg": 24.7, "count": 11 }
    ]
  }
}
Real-time WebSocket Events
Connect to wss://api.youriotcloud.io/ws?token=<access_token>. After connecting, subscribe to a device's feed. All messages are JSON with a type field.
↑ Client → Server: subscribe
Subscribe to real-time events for one or more devices
{
  "type": "subscribe",
  "device_ids": ["dev_01HXKN6D5E7F8G9H0J1K2L3M", "dev_02JYKP7E6..."]
}
// Server acknowledges:
{
  "type": "subscribed",
  "device_ids": ["dev_01HXKN6D5E7F8G9H0J1K2L3M"]
}
↓ Server → Client: telemetry.update
Pushed whenever a subscribed device sends a new sensor reading
{
  "type": "telemetry.update",
  "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
  "variable_id": "var_01HXKT1J0K2L3M4N5P6Q7R8S",
  "label": "temperature",
  "value": 25.3,
  "recorded_at": "2025-04-30T19:12:00Z"
}
↓ Server → Client: device.status
Pushed when a subscribed device comes online or goes offline
{
  "type": "device.status",
  "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
  "status": "online",
  "last_seen_at": "2025-04-30T19:12:01Z"
}
↓ Server → Client: command.status
Pushed whenever the status of a dispatched command changes (queued → sent → success/failed/expired)
{
  "type": "command.status",
  "instance_id": "cmi_01HXKX5N4P6Q7R8S9T0V1W2X",
  "command_name": "changeLevel",
  "device_id": "dev_01HXKN6D5E7F8G9H0J1K2L3M",
  "status": "success",
  "updated_at": "2025-04-30T19:12:05Z",
  "failure_reason": null
}
↑ Client → Server: unsubscribe
Stop receiving events for specific devices
{
  "type": "unsubscribe",
  "device_ids": ["dev_01HXKN6D5E7F8G9H0J1K2L3M"]
}
Standard error envelope
All error responses follow this shape. Frontend should check success: false and display error.message to users.
{
  "success": false,
  "error": {
    "code": "INVALID_PARAM_TYPE",
    "message": "Parameter 'level' expected integer, got string",
    "details": { "field": "level", "expected": "integer", "received": "string" }
  }
}