New: the AI firewall watches every module and explains each incident in plain words. See how it works

Device HTTP API

Every device endpoint over HTTPS – telemetry, attributes, command long poll and answers, device requests and provisioning – with examples and status codes.

Use HTTPS when a device cannot keep an MQTT connection: battery devices that wake up, send and sleep, or networks that block MQTT. HTTP messages are handled exactly like MQTT messages: the same payload forms, the same key rules, the same rate limits, the same monthly message count. This page lists every endpoint a device can call.

Basics

ItemValue
Base addressThe HTTPS telemetry address on the device’s Connection details card: the platform’s device host on port 443
LoginAuthorization: Bearer <device access token>
Content typeapplication/json; charset=utf-8
Body sizeUp to 64 KiB (the profile’s payload cap)
Plain HTTPPort 80 works where your installation offers it, but commands are then limited (see below). Use HTTPS.

The token never goes in the URL, except on profiles that turn on Token in the URL (see below). Client certificates are not used on the HTTP API: devices that log in with X.509 use MQTT. Any path that is not listed here answers 404.

Endpoints

MethodPathSame as MQTTBody or queryAnswer
POST/api/v1/telemetryv1/telemetrya telemetry payload200
POST/api/v1/attributesv1/attributesa client attributes object200
GET/api/v1/rpc?timeout=20000v1/rpc/req/{id}long poll, up to 60 sone command {"id":n,"method":…,"params":…}
POST/api/v1/rpc/{id}v1/rpc/res/{id}the command’s answer200
POST/api/v1/rpcv1/rpc/up/req/{id}{"method":…,"params":…}the cloud’s answer
POST/api/v1/provisionv1/provision/reqa provisioning request, no bearer headerthe provisioning answer
POST/api/v1/hellov1/hellothe device’s self-descriptionused by licensed-device firmware

Not available over HTTP: reading attributes (GET /api/v1/attributes), waiting for shared-attribute changes, opening the claim window and asking for firmware. These paths answer 404. Devices that need them use MQTT.

Telemetry uses the same payload forms as MQTT. See MQTT topics and payload reference. A body on POST /api/v1/telemetry that is not JSON is stored as one raw key (up to the profile’s raw size, 4 KB by default).

Endpoint details

POST/api/v1/telemetry

Send telemetry. Use any payload form: a flat object, an object with ts and values, or an array of both. Send Authorization: Bearer <device access token>. The answer 200 comes only after the message is safely queued; its body is empty.

Request body application/json

{
    "ts": 1759572000000,
    "values": {
        "temperature": 21.5,
        "humidity": 40
    }
}

Example curl

curl -X POST 'https://<your-host>/api/v1/telemetry' \
  -H 'Content-Type: application/json' \
  -d '{"ts":1759572000000,"values":{"temperature":21.5,"humidity":40}}'

Responses

200OK

No response body.

400Bad Request
{
    "error": "invalid_payload"
}
401Unauthorized

No response body.

413Payload Too Large
{
    "error": "payload_too_large"
}
429Too Many Requests
{
    "error": "rate_limited"
}
503Service Unavailable

No response body.

POST/api/v1/attributes

Send client attributes. Only the keys you send change.

Request body application/json

{
    "current_fw_title": "boiler-fw",
    "current_fw_version": "26.10.2",
    "lan.ip": "192.168.1.1"
}

Example curl

curl -X POST 'https://<your-host>/api/v1/attributes' \
  -H 'Content-Type: application/json' \
  -d '{"current_fw_title":"boiler-fw","current_fw_version":"26.10.2","lan.ip":"192.168.1.1"}'

Responses

200OK

No response body.

400Bad Request
{
    "error": "invalid_payload"
}
401Unauthorized

No response body.

429Too Many Requests
{
    "error": "rate_limited"
}

GET/api/v1/rpc?timeout=20000

Wait for the next command for this device (long poll, at most 60 seconds). Only one poll per device may be open at a time. Over a connection without TLS, a profile that allows no command without TLS answers 403.

Example curl

curl -X GET 'https://<your-host>/api/v1/rpc?timeout=20000'

Responses

200OK
{
    "id": 42,
    "method": "sys.ping",
    "params": {
        "host": "8.8.8.8",
        "count": 3
    }
}
403Forbidden
{
    "error": "tls_required"
}
408Request Timeout
{
    "error": "timeout"
}
409Conflict
{
    "error": "poll_in_progress"
}

POST/api/v1/rpc/{id}

Answer the command with this id. Use the same body as on MQTT v1/rpc/res/{id}.

Request body application/json

{
    "ok": true,
    "result": {
        "sent": 3,
        "received": 3,
        "avg_ms": 18.2
    }
}

Example curl

curl -X POST 'https://<your-host>/api/v1/rpc/{id}' \
  -H 'Content-Type: application/json' \
  -d '{"ok":true,"result":{"sent":3,"received":3,"avg_ms":18.2}}'

Responses

200OK

No response body.

413Payload Too Large
{
    "error": "payload_too_large"
}

POST/api/v1/rpc

Send a request from the device to the cloud, with method and params. Your flows answer it; the answer is the response body. If no answer comes within 10 seconds, the call answers 408. A body without method answers 400.

Request body application/json

{
    "method": "app.request",
    "params": {}
}

Example curl

curl -X POST 'https://<your-host>/api/v1/rpc' \
  -H 'Content-Type: application/json' \
  -d '{"method":"app.request","params":{}}'

Responses

200OK

No response body.

400Bad Request

No response body.

408Request Timeout
{
    "error": "timeout"
}

POST/api/v1/provision

Register a device with its profile’s provisioning key and secret. Send no bearer header. The call answers 200 with the provisioning answer; a refusal also answers 200, with "status": "FAILURE" and the reason in hermetry.error (for example {"status": "FAILURE", "hermetry": {"error": "rate_limited"}}). See Adding and claiming devices.

Request body application/json

{
    "deviceName": "boiler-07",
    "provisionDeviceKey": "pk_8f3b2c1e9d4a7b60",
    "provisionDeviceSecret": "ps_1c9e7f2a4b6d8e03"
}

Example curl

curl -X POST 'https://<your-host>/api/v1/provision' \
  -H 'Content-Type: application/json' \
  -d '{"deviceName":"boiler-07","provisionDeviceKey":"pk_8f3b2c1e9d4a7b60","provisionDeviceSecret":"ps_1c9e7f2a4b6d8e03"}'

Responses

200OK
{
    "status": "SUCCESS",
    "credentialsType": "ACCESS_TOKEN",
    "credentialsValue": "aZ3…"
}
413Payload Too Large
{
    "error": "payload_too_large"
}
503Service Unavailable

No response body.

Examples

Send one reading, stamped by the server:

curl -X POST "https://<device host>/api/v1/telemetry" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"temperature": 21.5, "humidity": 40}'

Send buffered readings with their own times (milliseconds since 1970, UTC):

curl -X POST "https://<device host>/api/v1/telemetry" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '[{"ts":1759572000000,"values":{"temperature":21.5}},{"ts":1759572060000,"values":{"temperature":21.7}}]'

Wait for a command and answer it:

curl -s "https://<device host>/api/v1/rpc?timeout=30000" -H "Authorization: Bearer <ACCESS_TOKEN>"
# → {"id": 42, "method": "sys.ping", "params": {...}}
curl -X POST "https://<device host>/api/v1/rpc/42" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" -H "Content-Type: application/json" \
  -d '{"ok": true, "result": {"sent": 3, "received": 3}}'

Status codes

CodeMeaning
200Accepted. Sent only after the message is safely queued.
400Invalid payload.
401Missing or unknown token.
403Device disabled, organisation suspended, address outside the profile’s allowed networks, or a command poll over plain HTTP that the profile does not allow (tls_required).
404Unknown path, or a URL token on a profile without Token in the URL.
408Long poll ended without data, or a device request got no answer in 10 seconds.
409Another command poll of this device is already open.
413Body too large.
429Rate limit, or too many requests or failed logins from your address. Wait the seconds in Retry-After.
503Overload. Wait the seconds in Retry-After.

Online status for HTTP devices

HTTP devices hold no connection, so a profile with Live connection never shows them online. Give HTTP devices a profile with Recent message (online while the last message is younger than the expected interval times the factor) or Last seen only. See Connection status and activity.

Devices that cannot send headers

Some devices cannot set an Authorization header. For them, turn on Token in the URL in the profile’s Transport & auth tab. The devices may then use:

POST /api/v1/{token}/telemetry
POST /api/v1/{token}/attributes

Warning

A token in a URL can leak through proxy logs and browser history. A profile with this switch on is HTTP-only: its devices cannot log in over MQTT and never receive commands. Give devices that can send headers a profile without the switch.

Commands over plain HTTP

A long poll that does not reach Hermetry over TLS receives only the commands the profile lists under Commands allowed without TLS. Every other command waits for a TLS connection or its expiry. If the list is empty, a plain poll answers 403 tls_required.