How a sensor sends its readings: the address and its key, the body, the answer for each reading, and the codes a call can meet.
A sensor of Hyz Assets sends its readings to its own endpoint, with its own key:
POST https://haiyz.net/api/sensors/<sensor id>/readings
Authorization: Bearer hyzsn_…
Content-Type: application/json
The sensor's page in Hyz Portal shows its address, its key's last four characters and a first request built from its channels. The key is made there (or in Hyz Console › Licenses and apps › Sensors) and shown once. It opens this endpoint and nothing else; it is not a session.
curl -X POST "https://haiyz.net/api/sensors/$SENSOR_ID/readings" \
-H "Authorization: Bearer $SENSOR_KEY" \
-H "Content-Type: application/json" \
-d '{"readings":[{"at":"2026-10-01T09:00:00Z","values":{"t1":41.5,"p1":3.1}}]}'
{ "readings": [
{ "at": "2026-10-01T09:00:00Z", "values": { "t1": 41.5, "p1": 3.1 } },
{ "at": "2026-10-01T09:01:00+03:00", "values": { "t1": 41.7 }, "location": [46.71, 24.69] }
] }
| Field | Is |
|---|---|
readings |
1 to 500 readings, within the API's 1 MB request body |
at |
the reading's time — the sensor's own — in ISO 8601 with its offset (Z or +03:00); a number of milliseconds is refused |
values |
the sensor's channels and their values: a number for a Number measurement, a whole number for a Whole number, true or false for a Yes / no |
location |
optional: [longitude, latitude] in degrees. It moves the asset's point on the live layer, and a rule's zone check reads it |
A reading needs a value or a location; one with neither is refused.
200, the platform's envelope with every reading accounted for in data:
{ "ok": true, "code": "SENSOR_READINGS_RESULT", "data": {
"accepted": ["2026-10-01T09:00:00.000Z"],
"duplicates": [],
"refused": [{ "at": "2026-10-01T09:01:00.000Z", "reason": "SENSOR_READING_UNKNOWN_CHANNEL", "channel": "t9" }]
} }
at
are the idempotency key, so a batch can always be sent again after a timeout.| Reason | The reading |
|---|---|
SENSOR_READING_AT_INVALID |
has no at, or one without its offset |
SENSOR_READING_IN_FUTURE |
is more than 10 minutes ahead — check the sensor's clock |
SENSOR_READING_TOO_OLD |
is older than the enterprise keeps readings |
SENSOR_READING_UNKNOWN_CHANNEL |
names a channel the sensor does not map |
SENSOR_READING_BAD_VALUE |
has a value not of its measurement's type, or says nothing |
SENSOR_READING_LOCATION |
has a location that is not [longitude, latitude] |
SENSOR_READING_DUPLICATE_IN_BATCH |
shares its time with another reading of the same call |
SENSOR_READINGS_DAILY_LIMIT |
came after the enterprise's readings for the day were spent |
| Status | Code | Why |
|---|---|---|
| 401 | SENSOR_KEY_INVALID |
one answer for every wrong case: no key, a wrong key, a revoked key, an unknown sensor |
| 403 | SENSOR_DISABLED |
the sensor is switched off |
| 403 | SENSOR_HELD |
Haiyz has switched the sensor off |
| 403 | ASSETS_HELD |
Haiyz has switched the enterprise's Hyz Assets off |
| 403 | ASSETS_SUSPENDED |
the enterprise is not active |
| 403 | LICENSE_FEATURE_MISSING |
a self-hosted instance whose licence lacks Hyz Assets |
| 400 | SENSOR_READINGS_BATCH_INVALID |
no reading, or more than 500 |
| 429 | SENSOR_RATE_LIMITED |
more calls this minute than the sensor may make (60 on Haiyz Cloud) |
| 429 | SENSOR_READINGS_DAILY_LIMIT |
the enterprise's readings for the day (UTC) are spent |
Each answer carries its message in English and Arabic beside its code; the envelope is documented once, on the API reference.