BluEM Quick Start

Read your energy monitor's data through the BluNotify Partner API, in six steps. For every route and field, see the reference; for how it all works, see the guide.

A BluEM unit measures one circuit. For each reporting period (15 minutes by default) it keeps an interval record: the average, lowest and highest voltage, current, power, frequency and power factor, plus its energy counter (a running total, like a utility meter's) at the start and end of the period. The API gives you three ways to read that data: the records themselves (steps 4 and 5), totals and averages the server works out across many records (step 3), and a reading taken from the meter right now (step 6). Every field name ends in its unit: 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},
     …}

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:

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.

  1. First call: GET …/intervals?received_since=2026-10-01T00:00:00Z, where received_since is the date your copy starts from.
  2. Save the records and the response's next_cursor together (in one database transaction, for example), so one is never saved without the other. The cursor is your bookmark, and it is never null.
  3. After that: GET …/intervals?cursor=<your bookmark>. While has_more is 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, …}, …}

Examples and client code

When something fails

ResponseWhat to do
401The key is missing, mistyped or revoked.
403Your key is missing a permission. required_permission in the response body names the one to ask BluNotify for.
404 not_foundNo such meter in your organization: check the device_id.
404 unknown_routeThe URL is wrong: check the base URL (https://api.blunotify.com/v1) and the path.
429Too 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.