WattWanneer

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.