Skip to content
BoilerBuddy

API

Sending readings

Uploading readings in batches of up to 1000, reading the answer, what to do with each rejection, and what happens to unknown sensor codes.

With POST /device/readings you upload readings, up to 1000 per batch. The answer tells you per reading what the server did with it, so you know exactly what you can remove from your buffer.

A batch

{
  "batch_uuid": "0d4f6c1e-8a51-4c43-9b6b-3c1f0f7a2e11",
  "readings": [
    {"sensor": "T1", "value": 61.4, "measured_at": "2026-10-08T11:59:00Z"},
    {"sensor": "R2", "value": 10, "measured_at": "2026-10-08T11:59:00Z"},
    {"sensor": "T3", "value": null, "quality": "no_response", "measured_at": "2026-10-08T11:59:00Z"}
  ]
}
Field Required Rule
readings yes 1 to 1000 readings, as a list
batch_uuid no A uuid. Keep it the same when you resend the same batch
clock no Clock anchor, only for clock correction: see Buffering and the clock

Per reading:

Field Required Rule
sensor yes A code from the device's configuration, such as T1. 1 to 16 characters: letters, digits, _, . and -. Case-sensitive
value yes, with ok A number. May be null or left out when quality is not ok
quality no ok (default), sensor_fault, out_of_range or no_response
measured_at yes When the value was read, ISO 8601 with a time zone
clock_synced, boot_id, mono_ns no Only for clock correction

Sending twice does no harm

A reading is unique per device, sensor and measured_at, to the second. Send it again and it counts under duplicates; the first value stays, even if the second one differs. Resending a batch after a timeout is therefore safe.

You may send batch_uuid and an Idempotency-Key header, but the server recognises duplicates by the readings themselves.

The answer

A batch that is valid as a whole gets 200, also when individual readings were rejected:

{
  "accepted": 2,
  "duplicates": 0,
  "unmapped": ["T9"],
  "rejected": [{"index": 3, "reason": "measured_at_in_future", "retry": false}]
}
Field Meaning
accepted Readings newly stored
duplicates Readings the server already had, including duplicates within this batch
unmapped Sensor codes that are not part of the device's circuit. Those readings are in quarantine and do not count towards accepted
rejected Per rejected reading: index (position in readings, from 0), reason and retry

Then remove the whole batch from your buffer, except the rejected readings with retry: true. Those go in a later batch.

422 means the batch is not valid as a whole: no or an empty readings, more than 1000 readings, or an invalid batch_uuid or clock. The answer has a message and the errors per field. Sending it again won't help: set the batch aside and look for the bug.

Rejections per reading

reason Meaning What to do
invalid_item The reading is not an object, or clock_synced is not true or false A bug in your software: fix it
invalid_sensor sensor is missing or does not match the pattern Fix it
invalid_value value is not a number, or its absolute value is above 10⁹ Fix it
value_required quality is ok (or missing) but there is no value No value? Send no_response or sensor_fault
invalid_quality Unknown value for quality Use one of the four values
invalid_measured_at Not a valid ISO 8601 timestamp with a time zone, or a date that does not exist Fix the format
measured_at_in_future More than 5 minutes ahead of the server's clock Your device's clock runs fast: check NTP
measured_at_too_old Older than 365 days Nothing: this reading can no longer be stored
clock_unsynced Taken with an unsynchronised clock, and it cannot be corrected With retry: true, keep it and send it later. See Buffering and the clock
too_many_unknown_sensors More than 16 different unknown codes in this batch Check your sensor codes
unmapped_quota_exceeded 25,000 readings already quarantined today (UTC) Check your sensor codes
batch_spans_too_many_days The reading falls on an eighth calendar day (UTC) in this batch Keep it (retry: true) and send it in a later batch

Only batch_spans_too_many_days, and clock_unsynced without a synchronised clock anchor, come with retry: true. All other rejections are final.

Unknown sensors

A code that is not part of the circuit goes into quarantine for 90 days, so a wiring or configuration mistake can be traced.

  • You won't see those readings in your charts or anywhere in the portal, and you cannot link them to a sensor afterwards.
  • On the device page, under API connection errors, a line with the number of rejected readings and the unknown codes appears at most once an hour.
  • Codes are case-sensitive: t1 is not T1.
  • Without a circuit, every code is unknown. Wait until the configuration has sensors before you upload: see Fetching the configuration.

Quality

quality When What happens
ok A normal reading Counts in charts, averages, minima and maxima
sensor_fault The sensor or controller reports a fault Stored, does not count. If it persists, the Sensor fault alert follows after ten minutes
out_of_range Read fine, but impossible Send the value. Stored, does not count
no_response The sensor or controller did not answer Value null. Stored, does not count

If a sensor sends no ok reading for a while (half an hour by default), the Sensor sends no reading alert follows. You can switch both alerts off per device under Alerts.

Timestamps and values

  • measured_at may be at most 5 minutes ahead and 365 days behind. The server truncates to whole seconds and stores in UTC.
  • One batch falls on at most 7 calendar days (UTC). If you send oldest first, a batch covers a day or two at most.
  • Send numbers, no greater than 10⁹ in absolute terms. A number as text ("61.4") is accepted too; other text, true or false gives invalid_value.
  • Send outputs such as pumps and valves as a number, the way the controller reports them: see Building your own BoilerBuddy.

All fields and types are in the API reference.

Stuck?

Ask your question through the contact form. We'll help you out and make this page better.

Contact us