Terug naar de API-documentatie
API technische documentatie
Elk endpoint geeft een andere doorsnede van dezelfde voorspelling terug, met eigen velden. Deze pagina zet ze allemaal op een rij: per endpoint welke velden erin zitten, welk type en welke eenheid ze hebben, en waar je ze in de praktijk voor gebruikt. Bedoeld voor wie zelf een energiemanager bouwt of de data in Home Assistant naar sensoren wil mappen.
Zoek je liever de voorbeelden en de koppelinstructies? Die staan op de API-pagina.
Afspraken die voor alle endpoints gelden
Deze vijf afspraken gelden overal. Wie ze kent, kan de rest van deze pagina overslaan en direct de tabellen induiken.
| Onderwerp | Afspraak |
|---|---|
| Base URL | https://wattwanneer.nl/api/v1/ |
| Authenticatie |
Header X-API-Key. Zonder of met een ongeldige key volgt HTTP 401 met
{"error": "invalid_api_key"}.
|
| Rate limit |
10 verzoeken per minuut per key, rollend venster. Daarboven HTTP 429 met
rate_limit_exceeded. Ruim voldoende voor een EMS: de voorspelling
verandert maar een keer per dag, dus een keer per uur ophalen is al meer dan
genoeg.
|
| Tijdstempels |
Altijd UTC in ISO 8601 met Z, bijvoorbeeld
2026-08-18T12:00:00Z. Een timestamp markeert het
begin van het uur waarvoor de prijs geldt. Reken zelf om naar
Europe/Amsterdam als je lokale uren nodig hebt: in de zomer is dat UTC plus 2, in
de winter UTC plus 1. De omzetting gebruikt de tijdzonedatabase, dus ook rond de
zomer- en wintertijdovergang staan de tijdstempels goed. De velden
date zijn wel al lokale NL-datums, zodat dagindelingen kloppen met
de kalender van je gebruiker.
|
| Horizon |
De reeks loopt 168 uur en begint bij het eerstvolgende hele etmaal,
niet bij het huidige uur. Zodra de dagelijkse run klaar is (zie hieronder) begint
de reeks dus bij morgen 00:00 lokale tijd, met de 24 gepubliceerde markturen
vooraan en daarachter 144 modeluren. Overweeg dit bij namen als
average_price_next_24h: dat is het gemiddelde over de eerste 24
punten van de reeks, in de praktijk dus morgen, en geen rollend venster vanaf nu.
Voor de uren van vandaag gebruik je
de pagina Vandaag of het publieke
today_prices.json.
|
| Prijzen |
In EUR per kWh, dus 0.0842 is 8,42 cent. Standaard kale
beursprijzen, exclusief inkoopvergoeding, energiebelasting en btw. Twee
endpoints kunnen dat voor je omrekenen naar een all-in tarief, zie
charges en vat hieronder.
|
Het belangrijkste veld voor je logica: source
Als je maar een ding uit deze pagina meeneemt, laat het dit zijn. Het veld
source vertelt of een uurprijs al vaststaat of nog een voorspelling is:
| Waarde | Betekenis | Wat je ermee doet |
|---|---|---|
entsoe_day_ahead |
De gepubliceerde marktprijs van de EPEX-veiling. Deze verandert niet meer. In de API zijn dit de eerste 24 punten van de reeks, dus de uren van morgen. | Hierop mag je hard schakelen: laden starten, batterij ontladen, boiler aan. Geen marge nodig. |
model |
Onze voorspelling, voor de uren die de markt nog niet heeft geveild. Dat is de horizon vanaf overmorgen tot zeven dagen vooruit. |
Gebruik dit om te plannen, niet om onherroepelijk te schakelen. Stel je
definitieve keuze uit tot de dag zelf, wanneer de prijs op
entsoe_day_ahead springt.
|
Een praktisch patroon voor een EMS: bepaal je weekplan op de modeluren, en herbereken zodra
er 24 nieuwe zekere uren binnenkomen. Dat gebeurt in de loop van de middag: de pipeline
draait rond 14:30 en 15:30 Nederlandse tijd, met een vangnet om 16:00 voor het geval de
marktprijzen laat gepubliceerd worden. Kijk naar generated_at om te zien
welke run je in handen hebt. Zo laadt je auto nooit op een voorspelling die inmiddels
achterhaald is, terwijl je wel een week vooruit kunt kijken.
Velden per endpoint
/v1/forecast
de ruwe basis
De volledige uurreeks. Alle andere endpoints zijn bewerkingen hiervan, dus wie zijn eigen
logica bouwt begint hier. Parameter: hours (1 tot 168, standaard 168).
| Veld | Type | Betekenis |
|---|---|---|
zone |
string | Marktgebied, altijd NL. |
generated_at |
string (UTC) | Wanneer deze voorspelling is gemaakt. Handig om te zien of je een verse run hebt; de pipeline draait dagelijks in de middag, rond 14:30 en 15:30 Nederlandse tijd, met een vangnet om 16:00. |
model_version |
string |
Welk model de voorspelling maakte, nu hist_gradient_boosting. Log dit
mee als je zelf nauwkeurigheid bijhoudt, dan kun je later modelwissels herkennen.
|
horizon_hours |
integer | Aantal punten dat je terugkrijgt, na toepassing van hours. |
points[] |
array | De uurreeks, chronologisch gesorteerd. |
points[].timestamp |
string (UTC) | Begin van het uur. |
points[].price_eur_per_kwh |
float | Kale prijs, 4 decimalen. Kan negatief zijn. |
points[].confidence_low |
float |
Onderkant van de onzekerheidsband. Let op: de band is altijd minimaal
1,2 cent breed aan elke kant, ook bij gepubliceerde marktprijzen die
niet meer veranderen. Lees de band dus niet als onzekerheid over een marktprijs;
gebruik daarvoor source.
|
points[].confidence_high |
float | Bovenkant van de band. Bij modeluren is het verschil tussen high en low een bruikbare risicomaat: is de band breder dan het minimum, wees dan terughoudend met onomkeerbare acties. |
points[].source |
string |
entsoe_day_ahead of model, zie de uitleg hierboven.
|
/v1/summary
samenvatting voor dashboards
Voorgekauwde kerncijfers, zodat je geen eigen min- en maxberekening hoeft te schrijven.
Parameter: windowHours (1 tot 24, standaard 3).
| Veld | Type | Betekenis |
|---|---|---|
zone |
string | Marktgebied, altijd NL. |
generated_at |
string (UTC) | Wanneer de onderliggende voorspelling is gemaakt. |
cheapest_hours_next_24h |
array (UTC) | De drie goedkoopste losse uren binnen de eerste 24 punten van de reeks, dus binnen morgen. Ideaal als Home Assistant-sensor met een attribuut per uur. |
cheapest_window |
object | Het goedkoopste aaneengesloten venster binnen de eerste 24 punten (morgen). |
cheapest_window.window_hours |
integer | Lengte van het venster, gelijk aan je windowHours. |
cheapest_window.start |
string (UTC) | Begin van het eerste uur in het venster. |
cheapest_window.end |
string (UTC) | Begin van het laatste uur in het venster. Let op: dit is niet het einde van het venster. |
cheapest_window.end_exclusive |
string (UTC) |
Het echte einde, een uur na end. Dit veld wil je gebruiken in
automations, anders schakel je een uur te vroeg uit.
|
cheapest_window.avg_price |
float | Gemiddelde kale prijs over het venster. |
average_price_next_24h |
float | Gemiddelde over de eerste 24 punten van de reeks, in de praktijk dus morgen. Bruikbaar als drempel: verbruik onder het daggemiddelde is een goed moment. |
average_price_next_7d |
float | Gemiddelde over de hele week. Vergelijk met de 24-uursversie om te zien of deze dag duur of goedkoop is in weekcontext. |
expected_peak_price_next_7d |
float | Hoogste verwachte uurprijs van de week. Voor batterij-eigenaren het richtpunt om ontlaadcapaciteit voor te reserveren. |
/v1/tariff
all-in feed voor evcc en Victron
Bewust een kale array zonder envelope, want dan werkt hij direct in evcc's custom tariff
zonder jq-filter. Parameters: hours (1 tot 168, standaard 168),
charges (0 tot 1 EUR per kWh) en vat (0 tot 30 procent).
| Veld | Type | Betekenis |
|---|---|---|
start |
string (UTC) | Begin van het uur. |
end |
string (UTC) |
Einde van het uur, dus exclusief. Anders dan bij summary hoef je hier
dus niets bij op te tellen.
|
value |
float |
De prijs in EUR per kWh, berekend als
(kale prijs + charges) * (1 + vat / 100), afgerond op 5 decimalen.
Laat je beide parameters weg, dan is dit gewoon de kale beursprijs.
|
Let op wat de opslag met negatieve prijzen doet. Bij een kale prijs van min 3 cent en een
opslag van 12 cent wordt value positief, en dat is ook correct: je betaalt
dan nog steeds belasting en vergoeding. Wil je weten wanneer de markt negatief
staat, gebruik dan /v1/negative-hours, dat rekent altijd op kale prijzen.
/v1/cheapest-hours
losse uren voor buffers
De N goedkoopste losse uren per kalenderdag, die dus niet aaneengesloten hoeven
te zijn. Voor warmtepompen, boilers en airco's die warmte of koude bufferen is dat
goedkoper dan een blok. Parameters: count (1 tot 12, standaard 6),
charges en vat werken hier ook.
| Veld | Type | Betekenis |
|---|---|---|
zone |
string | Marktgebied, altijd NL. |
generated_at |
string (UTC) | Wanneer de onderliggende voorspelling is gemaakt. |
hours_per_day |
integer | Je count, teruggegeven ter controle. |
days[].date |
string | Lokale NL-datum, dus 2026-08-18. |
days[].hours[].timestamp |
string (UTC) | Een van de geselecteerde uren, chronologisch gesorteerd. |
days[].hours[].price_eur_per_kwh |
float | Prijs van dat uur, inclusief je charges en vat. |
days[].avg_price_selected |
float | Gemiddelde prijs van de geselecteerde uren. |
days[].avg_price_day |
float | Gemiddelde over de hele dag, als referentie. |
days[].savings_vs_day_avg_pct |
float of null |
Hoeveel procent je bespaart door in die uren te draaien in plaats van willekeurig
over de dag. Handig om aan gebruikers te tonen dat de automatisering werkt.
null als het daggemiddelde nul of negatief is.
|
Randdagen worden overgeslagen als er minder uren beschikbaar zijn dan je
count, zodat je nooit een halve dag als volledige dag interpreteert.
/v1/negative-hours
teruglevering en gratis stroom
Alle uren waarvan de kale prijs onder je drempel zakt. Parameter:
threshold (min 1 tot 1 EUR per kWh, standaard 0). Zet hem op
0.02 om ook de bijna-gratis uren te pakken.
| Veld | Type | Betekenis |
|---|---|---|
zone |
string | Marktgebied, altijd NL. |
generated_at |
string (UTC) | Wanneer de onderliggende voorspelling is gemaakt. |
threshold_eur_per_kwh |
float | De gebruikte drempel. |
total_hours |
integer | Totaal aantal treffers in de hele week. Nul betekent simpelweg dat er niets te doen valt, dan kan je logica de teruglever-pauze overslaan. |
days[].date |
string | Lokale NL-datum. |
days[].hours[].timestamp |
string (UTC) | Het betreffende uur. |
days[].hours[].price_eur_per_kwh |
float | Kale prijs, hier dus zonder opslag of btw. |
days[].hours[].source |
string |
Of dit uur al vaststaat of nog voorspeld is. Voor het pauzeren van je omvormer wil
je wachten op entsoe_day_ahead.
|
note |
string | Herinnering dat het kale prijzen zijn en dat wat teruglevering jou kost van je contract afhangt. |
/v1/battery-plan
arbitrage per dag
Een arbitrage-indicatie per dag. Parameters: capacity_kwh (standaard 10),
power_kw (standaard 5) en efficiency (0.5 tot 1.0, standaard
0.9). Rekent met kale prijzen.
Lees dit niet als een uitvoerbaar schema. Het endpoint kiest per
kalenderdag simpelweg de goedkoopste uren om te laden en de duurste om te ontladen, en
garandeert niet dat het ontladen ná het laden valt. Op historische data gebeurt dat in
ongeveer een op de vijf dagen bij de standaardinstelling, en vaker bij een grotere
batterij: dan zou je moeten ontladen uit een batterij die volgens het plan nog niet
geladen is. Het endpoint kent ook je actuele laadstand niet. Gebruik het dus om te zien
of een dag de moeite waard is (worth_cycling, spread), en laat
je eigen regelaar bepalen wanneer er daadwerkelijk geschakeld wordt.
| Veld | Type | Betekenis |
|---|---|---|
zone |
string | Marktgebied, altijd NL. |
generated_at |
string (UTC) | Wanneer de onderliggende voorspelling is gemaakt. |
params.capacity_kwh |
float | Je meegegeven capaciteit, teruggegeven ter controle. |
params.power_kw |
float | Je meegegeven laad- en ontlaadvermogen. |
params.round_trip_efficiency |
float |
Je meegegeven efficiency, dus 0.9 voor 90 procent. Wordt volledig aan
de ontlaadkant verrekend.
|
params.charge_hours_needed |
integer | Aantal uren dat nodig is om vol te laden, berekend als capaciteit gedeeld door vermogen, naar boven afgerond. Bepaalt hoeveel uren er geselecteerd worden. |
days[].date |
string | Lokale NL-datum waarop dit plan geldt. |
days[].charge_hours |
array (UTC) | De goedkoopste uren van die dag, chronologisch. |
days[].avg_charge_price |
float | Gemiddelde inkoopprijs over die laaduren. |
days[].discharge_hours |
array (UTC) | De duurste uren, waarbij de laaduren zijn uitgesloten zodat je nooit in hetzelfde uur laadt en ontlaadt. |
days[].avg_discharge_price |
float | Gemiddelde prijs over de ontlaaduren. |
days[].spread_eur_per_kwh |
float | Het verschil tussen ontlaad- en laadprijs, nog zonder rendementsverlies. Je eigen drempel hangt af van je degradatiekosten. |
days[].estimated_profit_eur |
float |
Verwachte winst voor die dag:
capaciteit * (ontlaadprijs * rendement - laadprijs).
|
days[].worth_cycling |
boolean | Of de winst positief is. Het veld waar je automatisering op kan draaien, maar tel er je eigen slijtagedrempel bij op. |
best_day |
string of null | De datum met de hoogste verwachte winst deze week. |
assumptions |
string | Wat het model wel en niet meeneemt: een cyclus per dag, verlies aan de ontlaadkant, geen degradatiekosten. |
/v1/history
controleer ons
Gerealiseerde prijzen naast onze voorspelling van twee dagen eerder. Parameter:
days (1 tot 30, standaard 7).
| Veld | Type | Betekenis |
|---|---|---|
zone |
string | Marktgebied, altijd NL. |
generated_at |
string (UTC) | Wanneer de onderliggende voorspelling is gemaakt. |
days_returned |
integer | Je days, teruggegeven ter controle. |
points[].timestamp |
string (UTC) | Het uur. |
points[].price_realized |
float | Wat de prijs werkelijk werd. |
points[].price_forecast_2d |
float of null |
Wat wij twee dagen vooraf voorspelden. Dat is de eerste horizon die volledig
model is. null als er voor dat uur geen voorspelling bewaard is.
|
summary.hours_with_forecast |
integer | Aantal uren waarover de foutmaten zijn berekend. |
summary.mae_eur_per_kwh |
float of null | Gemiddelde absolute afwijking over die uren. |
summary.within_5ct_pct |
float of null | Percentage uren dat binnen 5 cent van de realisatie zat. |
note |
string | Uitleg waarom we juist de 2-daagse horizon tonen: dat is de eerste horizon die volledig model is, want dag 1 toont op de site al de echte day-ahead marktprijs. |
/v1/metrics
nauwkeurigheid van het model
Geen parameters. Leest de actuele rollende meting, niet een vaste waarde.
| Veld | Type | Betekenis |
|---|---|---|
model_version |
string | Actief model. |
mae_eur_per_kwh |
float | Gemiddelde absolute fout over het meetvenster. |
within_5_cent_pct |
float | Percentage uren binnen 5 cent. |
direction_accuracy_pct |
float | Hoe vaak de richting (stijgen of dalen) goed voorspeld is. Voor schakelbeslissingen vaak relevanter dan de absolute fout. |
three_hour_window_hit_rate |
float | Hoe vaak het voorspelde goedkoopste 3-uursvenster het werkelijke venster raakt. De meest praktijkgerichte maat die we hebben. |
window_start_error_hours |
float | Gemiddeld aantal uren dat de start van dat venster ernaast zat. |
n_samples_in_window |
integer | Aantal uren in de meting, normaal 168. |
r2 |
float | Verklaarde variantie van het model op de trainingsevaluatie. Meer een modelkwaliteitsmaat dan iets om je logica op te baseren. |
n_samples |
integer | Aantal uren waarop het model is getraind. |
last_backtest_range.from |
string | Begin van het meetvenster, lokale datum. |
last_backtest_range.to |
string | Einde van het meetvenster. |
Welk endpoint voor welke logica?
De vraag die je waarschijnlijk echt hebt: welke informatie voegt waar de meeste waarde toe? Dit is hoe wij het zouden indelen.
| Wat je wil regelen | Endpoint | Sleutelvelden |
|---|---|---|
| Auto laden, aaneengesloten blok | /v1/tariff of /v1/summary |
value, of cheapest_window.start plus end_exclusive |
| Warmtepomp of boiler, losse uren | /v1/cheapest-hours |
days[].hours[], savings_vs_day_avg_pct |
| Batterij: is deze dag het cycleren waard? | /v1/battery-plan |
worth_cycling, spread_eur_per_kwh (het schema zelf: eigen regelaar) |
| Teruglevering pauzeren of overschot opmaken | /v1/negative-hours |
total_hours, days[].hours[] |
| Eigen optimalisatie of ML | /v1/forecast |
alles, met name source en de confidence-band |
| Dashboard of notificatie | /v1/summary |
average_price_next_24h, expected_peak_price_next_7d |
| Eigen kwaliteitscontrole | /v1/history plus /v1/metrics |
price_forecast_2d tegen price_realized |
Bouw je een eigen EMS?
Dan zou ik /v1/forecast als enige bron nemen en de rest zelf berekenen. Je
hebt dan alle uren, de onzekerheidsband en het source-veld in handen, en je
houdt je optimalisatie in eigen beheer. De andere endpoints zijn vooral bedoeld om
standaardlogica uit handen te nemen, wat handig is als je juist niet alles zelf wil
bouwen. Eén verzoek per dag rond 14:00 volstaat; haal het eventueel elk uur op zodat je
de day-ahead-publicatie snel meepakt.
Home Assistant
Er is een kant-en-klare integratie: voeg
hercozandwijk/wattwanneer-homeassistant in HACS toe als custom repository
en je hebt zeven sensoren zonder zelf velden te mappen. Bouw je liever zelf, dan werkt
een rest-sensor op /v1/summary het prettigst, met de losse
waarden als attributen en de rest via templates. Voorbeelden voor sensoren, het
goedkoopste venster en een werkende automation staan
op de API-pagina onder Home Assistant koppelen.
Denk aan de tijdzone: Home Assistant toont lokale tijd, de API geeft UTC, dus gebruik
as_local() in je templates.
Mis je nog iets?
Deze referentie is er gekomen doordat een klant die zijn eigen energiemanager bouwt erom vroeg. Ontbreekt er een veld, of zou een extra endpoint je werk makkelijker maken? Laat het weten, dan kijk ik of het erin kan. De API groeit mee met wat gebruikers er daadwerkelijk mee doen.