Overview
The NOX Control Package provides access to:- Device information
- Energy consumption data.
- Forecasted consumption (= nomination)
- Actual consumption
- Typical consumption if NOX would not have altered the device steering.
- Changing user Settings
- Deleting a user
- Heat pump current state and forecasted state expressed as a Battery.
- Controling the heat pump by submitting a control schedule.
Getting Started
Prerequisites
- Valid NOX API key (see Authentication)
Base URL
All endpoints use the base URL:- Sandbox:
https://api.sandbox.nox.energy - Production:
https://api.nox.energy
Core Workflows
All our collection api endpoints use a
next_token to paginate through results if the size limit of the response has been reached.
To paginate through a response, you can use the next_token received in the response as a query parameter and call the same endpoint with
the same parameters again. You can repeat this process until you have received the last page of the response, which is signified
by the next_token field becoming null.1. Getting Device Information
To fetch all devices configuration data you can call the following endpoint:cURL
user_id and/or device_id in the
redirect_uri callback parameters. Use the parameters received from the redirect and the
/devices endpoint to fetch on a per user_id or per device_id basis.
This can be done using the query parameters like the below example:
cURL
device_id- Unique identifier per device. Each nox user_id can have multiple device_id’s.brand- Manufacturer brand of the device. We currently only support 1 heat pump brand per user. If a user has multiple brands, during the auth process, a new user_id is created.model_type- Signifies the type of device (e.g. air-to-water/air-to-air/… device)has_delayed_power_data_1d- Signifies if the device can or cannot provide real-time power data but instead provides its power data with a delay of 1 day between 2-4 AM UTC of the full previous day.
needs_reauthentication through our webhook. You can communicate to us which fields you are interested in and
we can set up a custom webhook with a POST endpoint you provide to us and you will receive real-time updates on change events.
We suggest you read Partner webhooks page for more info.
Alternatively, you can also use the /devices/telemetry/current endpoint to poll for current telemetry data.
This is only recommended if you are interested to show real time data temporarily for users when they are interacting with your app. This is not meant as a solution to have consistently higher granularity telemetry data.
If you want higher granularity telemetry data then we recommend you to use our webhook solution to receive real-time updates on change events.
A lot of query parameters exist on the /devices we recommend you to use them
if relevant, to reduces the size of data transfer.
2. Retrieving Consumption Data
2.1 Historical Consumption
Get actual measured consumption data of all devices of a certain timeframe:cURL
aggregated=true query parameter to
get the aggregated consumption across all devices.
If you are not interested in aggregated data but on a per device basis, you should use the query parameter device_id to get the consumption data on a per device basis.
Another option is to query without providing the device_id query parameter but loop over the same api call using the next_token query parameter
to paginate through the data of all devices. We would only recommend this option if you are interested in all devices data and if your timeframe you are querying is small (e.g. 15minutes)
as the amount of data can become quite large if you query a long timeframe and have many devices.
More info about the /device/consumption/historical endpoint.
2.2 Forecasted Consumption
Get forecasted (= nominated) consumption data for all devices of a certain timeframe:cURL
device_id query parameter.
More info about the /device/consumption/forecast/historical endpoint.
2.3 Typical Consumption:
Get baseline consumption:cURL
3. Managing User/Device Settings
Update user preferences and optimization settings on a per user/device basis. We recommend to directly go to the endpoint documentation of /devices/settings to seel all possible settings you can change. We recommend to at least implement the following settings options in your UI components of your website/app:- Preferred temperature
- Room comfort bounds
- Manufacturer schedule on/off
- Optimization Settings (but not flex trading as this is mutually exclusive with other optimizations and should only be enabled if you are a supplier that is using the partner control package)
- Location information for better forecasting and optimization results:
- Country
- Postal code
- Webhooks setup -> Real-time settings sync between all parties
4. Deleting a User
You can delete a single user. This operation will delete all data associated with the user_id. This is a irreversible operation and disconnects the devices. Once deleted, we can no longer provide energy consumption data of the devices of the user. We recommend to only use this endpoint if the user explicitly requests to delete their data from your side or when the user switches to another energy supplier. More info at the endpoint documentation of /user.5. Heat pumps as a thermal battery
This feature only exists if you are using the partner control package. If you are using the NOX control package, you can skip this section.
5.1 Getting Heat pump information representated as a thermal battery
Each heat pump is exposed as two independent parts: the domestic hot water (DHW) tank and the house. Two endpoints carry the model.current-state returns the measured thermal state and refreshes every 15 minutes; forecast returns the comfort bounds and the expected thermal behaviour as 15-minute records, 72 hours ahead, regenerated hourly.
This section works through a complete DHW scheduling decision and introduces each field at the point where it is used. The exhaustive field reference for both endpoints, including the deprecated Q_* variants, is in the API reference.
The battery model
The chart below shows the DHW tank of a single device over roughly 20 hours.
DHW_temperature (green) is the state of charge; upperbound_Z (red) and lowerbound_X (blue) are the limits it has to stay between. The steep declines are hot water draw-off, which you do not control. The sharp recoveries are heat pump activations, which you do.
Scheduling therefore reduces to one binary decision per 15-minute slot: activate, or do not. The rest of this section covers the data needed to make that decision well.
Establishing the current state
The scenario used throughout is a device at2025-01-15 11:58 UTC, with day-ahead prices low over the early afternoon and high from 17:00 onwards.
cURL
DHW_temperature is measured rather than predicted, which makes it the only defensible initial condition for a forward simulation. This endpoint is also what you poll to detect a device drifting towards its comfort bounds.
Comfort bounds and activation constraints
cURL
upperbound_Z and lowerbound_X delimit the usable capacity. At 60 °C and 42 °C respectively, a tank measuring 43.0 °C is close to depleted and has roughly 17 °C of headroom.
upperbound_Z is the appliance’s maximum DHW setpoint and is effectively constant. lowerbound_X is not. In the chart it rests at 42 °C but rises for isolated 15-minute intervals; each of those is positioned immediately ahead of hot water demand we expect the household to draw, and raises the floor to the temperature required to serve it. Treat such an interval as a deadline, the tank must be at least that warm by then. It is visible only in the forecast, never in the current state, which is the main reason to plan against the forecast rather than react to the measured temperature.
tank_activation_limit_temp is a hard precondition. A heat pump only initiates a DHW cycle once the tank has fallen below its own restart threshold, being the appliance’s maximum setpoint minus its hysteresis. We report that threshold; we do not impose it. At 43.0 °C the tank is below the 55 °C limit, so an activation will take effect. Above the limit, a request to heat the tank is accepted by the API and then produces nothing.
Y_avg is the midpoint of the comfort band, (60 + 42) / 2, and used as a reference to calculate T_loss, T_gain & P_if_activated, since these variables are temperature dependent. Y_avg is not a prediction of the tank temperature. It should not be used as the initial condition of a simulation.Activation profiles
T_gain and P_if_activated describe the consequences of activating. Both are arrays, because both change as an activation progresses.
Each array describes one activation, divided into consecutive quarter hours. Index 0 covers minutes 0–15 of that activation, index 1 minutes 15–30, and so on. T_gain is the temperature the water gains over each quarter, in °C; P_if_activated is the average electrical power drawn over the same quarter, in kW.
Tank profiles hold 4 values, covering 1 hour, since DHW cycles on most brands are shorter than that. Space heating and cooling profiles hold 8 values, covering 2 hours. To model an activation running beyond the end of an array, hold its last value.
P_if_activated typically increases across the array because the same activation becomes less efficient as it proceeds: a warmer tank requires a higher condensing temperature, which costs more electrical power per unit of heat delivered. That higher power is not available at a lower tank temperature, as heat exchanger sizing caps the input at any given temperature. Read side by side, the two arrays show the efficiency degrading over the cycle: 7.65 °C of gain for 2.37 kW in the first quarter, the same gain for 3.48 kW in the fourth.
Note that P_if_activated is returned in kW under both unit settings.
Standing loss and expected demand
T_loss is the temperature the tank loses over the record’s 15-minute slot if it is not activated. It is a scalar rather than an array, since the loss does not depend on how long the heat pump has been running.
It is not restricted to insulation losses. T_loss also carries the hot water we expect the household to draw during that interval, so it is a fraction of a degree overnight and can reach several degrees in an interval containing expected demand. Because the value varies per record, a forward simulation must read each record’s own T_loss rather than assume a constant.
Worked example: scheduling a DHW cycle
Starting from the measured 43.0 °C and using the 12:00 record, simulate an activation beginning at the next quarter hour. Per quarter, applyT_gain and subtract T_loss, stopping before upperbound_Z is crossed:
Two quarters fit; a third would exceed 60 °C. The activation runs from 12:00 to 12:30 and consumes
(2.37 + 2.89) × 0.25 h = 1.32 kWh.
That figure is also the answer to how much electrical energy the device can absorb at this moment: 1.32 kWh over 30 minutes, limited by the comfort bound rather than by the compressor rating. Priced against the corresponding day-ahead intervals, it can be compared directly against activating later in the day.
To establish when the next activation becomes necessary, continue the simulation past 12:30 without activating, subtracting each record’s T_loss and testing the result against that record’s lowerbound_X. Whichever occurs first, depletion to the standing floor, or a floor raised ahead of expected demand, sets the deadline.
The resulting decision is submitted as a schedule:
T_gain while activating and T_loss while not, constrain the trajectory to the bounds, and select the cheapest feasible schedule. Recompute as new data lands, current state every 15 minutes, forecast every hour, retain only the leading slots of each solution, and submit only when the plan changes.
Two refinements to the simulation.
T_gain is a gross gain, so the strict per-quarter update is +T_gain − T_loss; for the tank that correction is minor except in intervals carrying expected demand. And the profiles attached to a record are computed by simulating an activation starting from that record’s Y_avg, so their accuracy degrades as your simulated temperature diverges from the middle of the band.Space heating and cooling
The house battery follows the same structure under different field names:
The house additionally returns
Y_ideal, the temperature the user sees as his ideal temperature between their comfort bounds.
Simulation is identical in form: apply T_heating or T_cooling per quarter while activating and T_natural while not, and keep the trajectory within lowerbound_X and upperbound_Z.
Units
Every example above usesunit=celsius. The endpoints still default to unit=kWh, which returns the same model with state and bounds expressed in kWh and thermal flows as Q_loss / Q_gain / Q_natural in kW. We intend to phase that representation out.
Migration carries no functional cost. The P_* fields are returned in kW under either setting, so energy, cost and consumption reporting are unaffected by the change.
Call frequency
The forecast is most accurate over approximately the first 12 hours and degrades gradually beyond that, being dependent on weather forecasts and occupant behaviour. Because it is regenerated hourly, querying it once per hour always returns the current best prediction; polling more frequently returns the same data.
Comfort bounds should not be cached. They change when the heat pump switches between heating and cooling operation, and when the user modifies their comfort settings.
5.2 Controlling the heat pump
This feature only exists if you are using the partner control package. If you are using the NOX control package, you can skip this section.
POST /device/thermal-control/schedule. The schedule has 96 slots of 15 minutes each, starting from the next quarter-hour (e.g. submit at 10:07 → the schedule runs from 10:15 to 10:00 the next day). Only submit a new schedule when you actually want to change it.
cURL
The
house_heating, house_cooling, and tank arrays are shortened to 8 values (2 hours) above for readability. A real request must always send exactly 96 values, one per 15-minute slot covering the next 24 hours.house_heating/house_cooling/tank– arrays of 96 booleans that switch space heating, space cooling, or DHW tank heating on/off for that slot. Only sethouse_coolingslots totruefor devices wherehas_coolingistrue(seesteerable_statusbelow).timestamp– optional, defaults to the next quarter-hour. If provided, it must land exactly on a quarter-hour boundary in the future.
steerable_status from /devices: steering_enabled and steerable must both be true, and DHW.can_activate_action / room.can_activate_action tell you whether the tank/house can currently accept a new schedule. If steerable is false, general_reason explains why (e.g. reauthentication required, too many heating zones, still learning the device).
Failsafes you don’t control:
- DHW tank heating never runs for more than 1 continuous hour, no matter what the schedule says, unless the following field
dhw_max_cycle_timeincycle_configis set to a higher value than 60 minutes in the devices endpoint. - If the tank or house temperature drifts outside its comfort bounds, we override the schedule with a failsafe heat/cool action until it’s back in bounds.
Next Steps
- Set up Partner Webhooks for real-time data updates.