voltage_v is
volts, current_a amps, power_w watts, frequency_hz hertz and
energy_wh watt-hours. power_factor has no unit.1. Get a key
BluNotify staff issue API keys. Ask for the Energy data read permission
(energy_read) for the organization your meters are in; it is the only permission this
guide needs. Keep the key secret: send it in the Authorization header of each request, and
never put it in a URL or anywhere else.
curl https://api.blunotify.com/v1/account -H "Authorization: Bearer $KEY"
200 {"partner":{"name":"…","permissions":{"energy_read":true, …}, …}}
2. Find your meter
curl "https://api.blunotify.com/v1/devices?product=bluem" -H "Authorization: Bearer $KEY"
200 {"devices":[{"device_id":"7C9EBD91235C","name":"Walk-in freezer","product":"bluem"}]}
Use device_id in every request below. Asking for a meter outside your organization
returns 404, exactly as if it did not exist.
3. Read a summary
The quickest way to see how a circuit behaved over a period: the server goes through the records in
the time window you ask for and returns averages, lows, highs and the energy used. start
and end are ISO 8601 times or epoch seconds; leave them out to get the last 24 hours.
curl "https://api.blunotify.com/v1/bluem/devices/7C9EBD91235C/summary?start=2026-09-29T14:00:00Z&end=2026-09-30T14:00:00Z" \
-H "Authorization: Bearer $KEY"
200 {"device_id":"7C9EBD91235C",
"window":{"start":"2026-09-29T14:00:00+00:00","end":"2026-09-30T14:00:00+00:00"},
"coverage":{"records":96,"quarantined":0,"seconds":86391},
"voltage_v": {"avg":123.077838,"min":119.6,"max":125.3, "intervals":96,"seconds":86391},
"power_w": {"avg":31.99751, "min":0.0, "max":764.92,"intervals":96,"seconds":86391},
"power_factor":{"avg":0.693137, "min":0.0, "max":0.96, "intervals":55,"seconds":49493},
"energy_wh":{"total":769.0,"resets":0,"intervals":96},
…}
energy_wh.totalis the energy used, in watt-hours: 769.0 Wh is 0.769 kWh.- Each average gives every record weight in proportion to how long it lasted.
minandmaxare the lowest and highest values any record saw, not the lowest and highest averages.power_factorcovers only the intervals when the circuit was drawing power. - A quantity with no reading in the window is
null, never 0.coverageshows how much of the window has data: comparecoverage.secondswith the window's length (86,400 for a day). - For consumption per hour or per day (in your own time zone with
tz), useGET …/energy.
4. Page through the records
For your own analysis, read the records themselves, up to 1000 per page. Each page carries a
next_cursor: send it back to get the next page, until has_more is false.
import requests # pip install requests
url = "https://api.blunotify.com/v1/bluem/devices/7C9EBD91235C/intervals"
params = {"start": "2026-09-29T14:00:00Z", "end": "2026-09-30T14:00:00Z", "limit": 1000}
headers = {"Authorization": f"Bearer {key}"}
records = []
while True:
r = requests.get(url, params=params, headers=headers, timeout=30)
r.raise_for_status() # stops with an error on any failure (401, 403, 429, ...)
page = r.json()
records += page["records"]
if not page["has_more"]:
break
params = {"cursor": page["next_cursor"], "limit": 1000}
Each record has start_at, duration_s, and an avg,
min and max for each quantity. Two things to plan for:
- Not every interval is 15 minutes. A restart or an on-demand report makes a shorter one.
Weight by
duration_s; never assume 900 seconds. - The cursor remembers your
startandend. You can leave them out when you ask for later pages, as the code above does. If you do send them, they must not change.
5. Keep your own copy
A meter that loses its connection keeps its records and sends them when it reconnects, sometimes days later. If you fetch by time range (say, "the last hour", every hour), you miss any record that arrives after you fetched its hour. To keep a complete copy, follow the arrival feed instead: every record, in the order the server stored it.
- First call:
GET …/intervals?received_since=2026-10-01T00:00:00Z, wherereceived_sinceis the date your copy starts from. - Save the records and the response's
next_cursortogether (in one database transaction, for example), so one is never saved without the other. The cursor is your bookmark, and it is nevernull. - After that:
GET …/intervals?cursor=<your bookmark>. Whilehas_moreis true, ask again right away; when it is false, check back later (every few minutes is plenty).
Use sid and seq together as each record's unique key; then a record you
receive twice is never stored twice. The guide has the full rules.
6. Take a live reading
What the meter reads right now, without waiting for the current interval to end. Send a
POST, then poll the URL in the response's Location header every second or two
until state is no longer pending. That usually takes one to three seconds, and
never more than 30.
curl -X POST https://api.blunotify.com/v1/bluem/devices/7C9EBD91235C/sample \
-H "Authorization: Bearer $KEY"
202 Location: /v1/bluem/devices/7C9EBD91235C/sample/5f3a9c1e
{"device_id":"7C9EBD91235C","token":"5f3a9c1e","state":"pending", …}
curl https://api.blunotify.com/v1/bluem/devices/7C9EBD91235C/sample/5f3a9c1e \
-H "Authorization: Bearer $KEY"
200 {"state":"done",
"reading":{"voltage_v":122.0,"current_a":0.6268,"power_w":58.54,"power_factor":0.77,
"frequency_hz":60.0,"answered":true,"took_s":1.278, …}, …}
- If the meter is not connected, the
POSTreturns409 device_offlineand nothing is sent to the meter. - Each meter allows one live reading every 10 seconds, no matter who asks. A request sooner than that
gets
429, with aRetry-Afterheader. - A live reading is not stored; it never appears among the records.
Examples and client code
- Example programs in Python and Java: BluNotify staff send them together with your API key. They read a meter's records for the last 24 hours, print its statistics, and work out how much of that time the load was running.
- Generate a client. /openapi.json is a standard OpenAPI 3.1
description, so code generators can build a typed client from it; for Python, for example,
openapi-python-client generate --url https://api.blunotify.com/openapi.json. - Every route and field is in the reference; the concepts and the integrator notes are in the guide; changes since launch are in the changelog.
When something fails
| Response | What to do |
|---|---|
401 | The key is missing, mistyped or revoked. |
403 | Your key is missing a permission. required_permission
in the response body names the one to ask BluNotify for. |
404 not_found | No such meter in your organization: check the
device_id. |
404 unknown_route | The URL is wrong: check the base URL
(https://api.blunotify.com/v1) and the path. |
429 | Too many requests: wait Retry-After seconds. Every response
carries RateLimit-Remaining, so you can slow down before you reach the limit. |
Every error is JSON with error, code and request_id. When you
contact BluNotify support, include the request_id (also sent as the
X-Request-Id header): it lets us find your exact request.