curl --request POST \
--url https://api.nox.energy/v1/devices/battery/schedules \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
[
{
"device_id": "e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c",
"schedules": [
{
"start_time": "2026-10-17T11:00:00Z",
"end_time": "2026-10-17T14:00:00Z",
"mode": "pause_charge"
},
{
"start_time": "2026-10-17T18:00:00Z",
"end_time": "2026-10-17T19:30:00Z",
"mode": "force_discharge"
}
]
},
{
"device_id": "1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c",
"schedules": [
{
"start_time": "2026-10-17T02:00:00Z",
"end_time": "2026-10-17T04:00:00Z",
"mode": "force_charge"
}
]
}
]
'import requests
url = "https://api.nox.energy/v1/devices/battery/schedules"
payload = [
{
"device_id": "e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c",
"schedules": [
{
"start_time": "2026-10-17T11:00:00Z",
"end_time": "2026-10-17T14:00:00Z",
"mode": "pause_charge"
},
{
"start_time": "2026-10-17T18:00:00Z",
"end_time": "2026-10-17T19:30:00Z",
"mode": "force_discharge"
}
]
},
{
"device_id": "1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c",
"schedules": [
{
"start_time": "2026-10-17T02:00:00Z",
"end_time": "2026-10-17T04:00:00Z",
"mode": "force_charge"
}
]
}
]
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify([
{
device_id: 'e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c',
schedules: [
{
start_time: '2026-10-17T11:00:00Z',
end_time: '2026-10-17T14:00:00Z',
mode: 'pause_charge'
},
{
start_time: '2026-10-17T18:00:00Z',
end_time: '2026-10-17T19:30:00Z',
mode: 'force_discharge'
}
]
},
{
device_id: '1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c',
schedules: [
{
start_time: '2026-10-17T02:00:00Z',
end_time: '2026-10-17T04:00:00Z',
mode: 'force_charge'
}
]
}
])
};
fetch('https://api.nox.energy/v1/devices/battery/schedules', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nox.energy/v1/devices/battery/schedules",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
[
'device_id' => 'e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c',
'schedules' => [
[
'start_time' => '2026-10-17T11:00:00Z',
'end_time' => '2026-10-17T14:00:00Z',
'mode' => 'pause_charge'
],
[
'start_time' => '2026-10-17T18:00:00Z',
'end_time' => '2026-10-17T19:30:00Z',
'mode' => 'force_discharge'
]
]
],
[
'device_id' => '1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c',
'schedules' => [
[
'start_time' => '2026-10-17T02:00:00Z',
'end_time' => '2026-10-17T04:00:00Z',
'mode' => 'force_charge'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.nox.energy/v1/devices/battery/schedules"
payload := strings.NewReader("[\n {\n \"device_id\": \"e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T11:00:00Z\",\n \"end_time\": \"2026-10-17T14:00:00Z\",\n \"mode\": \"pause_charge\"\n },\n {\n \"start_time\": \"2026-10-17T18:00:00Z\",\n \"end_time\": \"2026-10-17T19:30:00Z\",\n \"mode\": \"force_discharge\"\n }\n ]\n },\n {\n \"device_id\": \"1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T02:00:00Z\",\n \"end_time\": \"2026-10-17T04:00:00Z\",\n \"mode\": \"force_charge\"\n }\n ]\n }\n]")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.nox.energy/v1/devices/battery/schedules")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("[\n {\n \"device_id\": \"e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T11:00:00Z\",\n \"end_time\": \"2026-10-17T14:00:00Z\",\n \"mode\": \"pause_charge\"\n },\n {\n \"start_time\": \"2026-10-17T18:00:00Z\",\n \"end_time\": \"2026-10-17T19:30:00Z\",\n \"mode\": \"force_discharge\"\n }\n ]\n },\n {\n \"device_id\": \"1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T02:00:00Z\",\n \"end_time\": \"2026-10-17T04:00:00Z\",\n \"mode\": \"force_charge\"\n }\n ]\n }\n]")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nox.energy/v1/devices/battery/schedules")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "[\n {\n \"device_id\": \"e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T11:00:00Z\",\n \"end_time\": \"2026-10-17T14:00:00Z\",\n \"mode\": \"pause_charge\"\n },\n {\n \"start_time\": \"2026-10-17T18:00:00Z\",\n \"end_time\": \"2026-10-17T19:30:00Z\",\n \"mode\": \"force_discharge\"\n }\n ]\n },\n {\n \"device_id\": \"1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T02:00:00Z\",\n \"end_time\": \"2026-10-17T04:00:00Z\",\n \"mode\": \"force_charge\"\n }\n ]\n }\n]"
response = http.request(request)
puts response.read_body{
"rejected": [],
"meta": {
"energy_supplier": "Energy Supplier A",
"accepted_count": 2,
"rejected_count": 0
}
}{
"rejected": [
{
"device_id": "1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c",
"reason": "The requested mode is not in the allowed_modes of this battery.",
"reason_code": 5
}
],
"meta": {
"energy_supplier": "Energy Supplier A",
"accepted_count": 1,
"rejected_count": 1
}
}{
"detail": "None of the provided device_ids allow steering or are compatible."
}{
"detail": "Energy Supplier A is not authorized to access this feature."
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}{
"detail": "This endpoint is not available yet."
}Post Battery Control Schedule
Preview: not available yet. This endpoint is documented ahead of its release and currently
answers 501 Not Implemented. Its contract may still change before release.
Submit battery schedules: per battery, a list of time windows with the battery mode to apply.
Schedules are only accepted for batteries with flex_trading enabled in their settings
(see PATCH /v1/devices/battery/settings).
mode can be set to:
-
auto(default): the battery follows its own logic. Pv surplus charges the battery, the battery covers the house load, the grid covers the rest. The battery returns toautooutside your schedules and whenever NOX Energy takes over. -
pause_charge: the battery does not charge. Pv surplus is exported, the battery can still discharge. -
pause_discharge: the battery does not discharge. The grid covers the house load, pv surplus can still charge the battery. -
force_charge: the battery charges at its fixed charge power, from pv first and from the grid for the rest. -
force_discharge: the battery discharges at its fixed discharge power, to the house first and to the grid for the rest. Only while the state of charge is abovemin_soc_pct: when it reaches that limit, NOX Energy takes control and puts the battery inautofor the rest of the entry.
Only the modes in the battery’s allowed_modes are accepted. Outside your time windows the battery
falls back to auto. A force_discharge entry that starts while the state of charge is already at
or below min_soc_pct is accepted, but the battery stays in auto until the entry ends.
When you send a new schedule for a battery, it replaces every schedule previously sent for that battery. You can send schedules for many batteries in one request.
Timestamp fields in UTC.
Time format examples:
-
2023-10-01T00:00:00Z
-
2023-10-01T00:00:00
NOTE:
- The battery might need some time to react.
start_timemust be at least 1 minute in the future.
curl --request POST \
--url https://api.nox.energy/v1/devices/battery/schedules \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
[
{
"device_id": "e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c",
"schedules": [
{
"start_time": "2026-10-17T11:00:00Z",
"end_time": "2026-10-17T14:00:00Z",
"mode": "pause_charge"
},
{
"start_time": "2026-10-17T18:00:00Z",
"end_time": "2026-10-17T19:30:00Z",
"mode": "force_discharge"
}
]
},
{
"device_id": "1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c",
"schedules": [
{
"start_time": "2026-10-17T02:00:00Z",
"end_time": "2026-10-17T04:00:00Z",
"mode": "force_charge"
}
]
}
]
'import requests
url = "https://api.nox.energy/v1/devices/battery/schedules"
payload = [
{
"device_id": "e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c",
"schedules": [
{
"start_time": "2026-10-17T11:00:00Z",
"end_time": "2026-10-17T14:00:00Z",
"mode": "pause_charge"
},
{
"start_time": "2026-10-17T18:00:00Z",
"end_time": "2026-10-17T19:30:00Z",
"mode": "force_discharge"
}
]
},
{
"device_id": "1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c",
"schedules": [
{
"start_time": "2026-10-17T02:00:00Z",
"end_time": "2026-10-17T04:00:00Z",
"mode": "force_charge"
}
]
}
]
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify([
{
device_id: 'e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c',
schedules: [
{
start_time: '2026-10-17T11:00:00Z',
end_time: '2026-10-17T14:00:00Z',
mode: 'pause_charge'
},
{
start_time: '2026-10-17T18:00:00Z',
end_time: '2026-10-17T19:30:00Z',
mode: 'force_discharge'
}
]
},
{
device_id: '1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c',
schedules: [
{
start_time: '2026-10-17T02:00:00Z',
end_time: '2026-10-17T04:00:00Z',
mode: 'force_charge'
}
]
}
])
};
fetch('https://api.nox.energy/v1/devices/battery/schedules', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nox.energy/v1/devices/battery/schedules",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
[
'device_id' => 'e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c',
'schedules' => [
[
'start_time' => '2026-10-17T11:00:00Z',
'end_time' => '2026-10-17T14:00:00Z',
'mode' => 'pause_charge'
],
[
'start_time' => '2026-10-17T18:00:00Z',
'end_time' => '2026-10-17T19:30:00Z',
'mode' => 'force_discharge'
]
]
],
[
'device_id' => '1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c',
'schedules' => [
[
'start_time' => '2026-10-17T02:00:00Z',
'end_time' => '2026-10-17T04:00:00Z',
'mode' => 'force_charge'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.nox.energy/v1/devices/battery/schedules"
payload := strings.NewReader("[\n {\n \"device_id\": \"e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T11:00:00Z\",\n \"end_time\": \"2026-10-17T14:00:00Z\",\n \"mode\": \"pause_charge\"\n },\n {\n \"start_time\": \"2026-10-17T18:00:00Z\",\n \"end_time\": \"2026-10-17T19:30:00Z\",\n \"mode\": \"force_discharge\"\n }\n ]\n },\n {\n \"device_id\": \"1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T02:00:00Z\",\n \"end_time\": \"2026-10-17T04:00:00Z\",\n \"mode\": \"force_charge\"\n }\n ]\n }\n]")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.nox.energy/v1/devices/battery/schedules")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("[\n {\n \"device_id\": \"e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T11:00:00Z\",\n \"end_time\": \"2026-10-17T14:00:00Z\",\n \"mode\": \"pause_charge\"\n },\n {\n \"start_time\": \"2026-10-17T18:00:00Z\",\n \"end_time\": \"2026-10-17T19:30:00Z\",\n \"mode\": \"force_discharge\"\n }\n ]\n },\n {\n \"device_id\": \"1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T02:00:00Z\",\n \"end_time\": \"2026-10-17T04:00:00Z\",\n \"mode\": \"force_charge\"\n }\n ]\n }\n]")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nox.energy/v1/devices/battery/schedules")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "[\n {\n \"device_id\": \"e4da3b7f-bbce-4a45-9d2b-1c0e8f7a6b5c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T11:00:00Z\",\n \"end_time\": \"2026-10-17T14:00:00Z\",\n \"mode\": \"pause_charge\"\n },\n {\n \"start_time\": \"2026-10-17T18:00:00Z\",\n \"end_time\": \"2026-10-17T19:30:00Z\",\n \"mode\": \"force_discharge\"\n }\n ]\n },\n {\n \"device_id\": \"1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c\",\n \"schedules\": [\n {\n \"start_time\": \"2026-10-17T02:00:00Z\",\n \"end_time\": \"2026-10-17T04:00:00Z\",\n \"mode\": \"force_charge\"\n }\n ]\n }\n]"
response = http.request(request)
puts response.read_body{
"rejected": [],
"meta": {
"energy_supplier": "Energy Supplier A",
"accepted_count": 2,
"rejected_count": 0
}
}{
"rejected": [
{
"device_id": "1679091c-5a88-4c2f-8e1d-3b2a0f9e8d7c",
"reason": "The requested mode is not in the allowed_modes of this battery.",
"reason_code": 5
}
],
"meta": {
"energy_supplier": "Energy Supplier A",
"accepted_count": 1,
"rejected_count": 1
}
}{
"detail": "None of the provided device_ids allow steering or are compatible."
}{
"detail": "Energy Supplier A is not authorized to access this feature."
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}{
"detail": "This endpoint is not available yet."
}Authorizations
API Key authentication. Enter your API key in the format: YOUR_API_KEY