WattWanneer API v2
Drie endpoints, gebouwd voor Homey en voor andere integraties die verder willen kijken dan morgenavond. Ze zitten in hetzelfde abonnement als de v1-endpoints en vereisen dezelfde persoonlijke API-key.
| Endpoint | Waarvoor |
|---|---|
GET /api/v2/prices | Prijzen vanaf het lopende uur, met je eigen afname- en teruglevertarief. Voor zonnepanelen en energiemanagement. |
GET /api/v2/charge-plan | Laadplan met een vertrekdeadline. Voor elektrisch rijden. |
POST /api/v2/battery-plan | Uitvoerbaar laad-, ontlaad- en bewaarplan. Voor thuisbatterijen. |
De bestaande v1-endpoints blijven ongewijzigd werken. Er is geen migratie nodig en je huidige Home Assistant-configuratie verandert niet.
Authenticatie en limieten
Stuur je persoonlijke key mee als header X-API-Key. Zonder geldige key
volgt een 401. Een 429 betekent dat je de limiet raakt.
curl -H "X-API-Key: JOUW_API_KEY" \ "https://wattwanneer.nl/api/v2/prices?from=now&hours=24"
| Wat | v1 | v2 |
|---|---|---|
| Limiet per minuut per key | 10 | 20 |
| Teller | eigen | eigen, apart van v1 |
De tellers staan los van elkaar. Gebruik je dezelfde key in Home Assistant en in Homey, dan eten die elkaars ruimte niet op. Toegang wordt bij elke aanvraag server-side gecontroleerd, ook wanneer de prijsreeks uit de cache komt.
Voor gebruik in een dienst voor anderen geldt het zakelijke abonnement.
Gedeelde afspraken
| Onderwerp | Afspraak |
|---|---|
| Tijdstempels | Altijd UTC met Z. Invoer zonder offset wordt als Nederlandse tijd gelezen. |
| Intervallen | start inclusief, end exclusief. Bronresolutie is een uur. |
| Prijzen | EUR per kWh. |
| Energie | kWh. Vermogen in kW. Laadstand in procent van de capaciteit. |
| Klokwisseling | Een lokaal etmaal heeft 23, 24 of 25 uur. Elke berekening gebruikt de werkelijke intervalduur. |
| Herkomst | source is market voor een gepubliceerde prijs en forecast voor een voorspelling. |
| Ontbrekende waarden | Worden gemeld, nooit stilzwijgend nul. |
| Momentopname | Binnen één aanvraag werken alle berekeningen op hetzelfde bevroren beeld van de bronnen. |
Datastatus
| Waarde | Betekenis |
|---|---|
ok | Volledige dekking, geen hiaten, verse bron. |
partial | Minder intervallen dan gevraagd, of hiaten in de reeks. |
stale | De nieuwste bron is ouder dan 36 uur, dus er is minstens één pijplijnrun gemist. |
unavailable | Geen bruikbare intervallen. |
Tarieven: afname en teruglevering apart
Een kale beursprijs is geen persoonlijk tarief. Geef je geen
tariefinstellingen mee, dan blijven import_eur_per_kwh en
export_eur_per_kwh op null staan en zegt
tariff_assumptions.warnings waarom. market_eur_per_kwh is
altijd de kale beursprijs.
import = (markt + supply_surcharge + energy_tax) * (1 + vat_pct/100)
export = max(markt - feed_in_deduction,
feed_in_floor_pct% * (markt + supply_surcharge)) * (1 + feed_in_vat_pct/100)
| Parameter | Eenheid | Standaard | Betekenis |
|---|---|---|---|
supply_surcharge | EUR/kWh | null | Inkoopopslag van je leverancier, exclusief btw. Mag negatief. |
energy_tax | EUR/kWh | null | Energiebelasting exclusief btw. Eerste schijf 2026 is 0.09161. |
vat_pct | procent | null | Btw over de afnameprijs. In Nederland 21. |
feed_in_deduction | EUR/kWh | null | Wat je leverancier inhoudt per teruggeleverde kWh. Negatief als je een toeslag krijgt. |
feed_in_floor_pct | procent | null | Wettelijke ondergrens als percentage van het kale leveringstarief. Vanaf 2027 is dat 50. |
feed_in_vat_pct | procent | null | Btw over de terugleververgoeding. |
Wat er bewust niet in zit
- Vaste terugleverkosten per maand of per jaar. Die zijn niet eerlijk per kWh toe te rekenen.
- Vastrecht, netbeheerkosten en de heffingskorting. Dat zijn kosten per aansluiting.
- Saldering. Of en hoe er wordt gesaldeerd hangt af van je contract en het jaar, dus dat rekenen we niet ongevraagd mee.
- De wettelijke bodem staat standaard uit. Hij geldt niet voor elk contract en niet in elk jaar, dus je zet hem zelf aan.
Een negatieve beursprijs is geen opdracht om je zonnepanelen uit te schakelen. Wat
teruglevering je oplevert staat in export_eur_per_kwh, en dat hangt af
van je contract.
GET /api/v2/prices
Eén chronologische reeks vanaf het lopende uur, waarin gepubliceerde day-ahead prijzen en modelvoorspellingen zijn samengevoegd. Een gepubliceerde prijs wint altijd van een voorspelling voor hetzelfde uur.
| Parameter | Standaard | Bereik | Betekenis |
|---|---|---|---|
from | now | alleen now | Startmoment. |
hours | 168 | 1 tot 192 | Aantal uurintervallen. Er komen er minder terug als de reeks eerder ophoudt. |
| Plus alle tariefparameters uit de tabel hierboven. | |||
{
"zone": "NL",
"timezone": "Europe/Amsterdam",
"currency": "EUR",
"energy_unit": "kWh",
"interval_minutes": 60,
"source_resolution_minutes": 60,
"requested_from": "2026-09-08T12:30:00Z",
"coverage_start": "2026-09-08T12:00:00Z",
"coverage_end": "2026-09-14T12:00:00Z",
"intervals_requested": 168,
"intervals_returned": 168,
"intervals_market": 34,
"intervals_forecast": 134,
"missing_intervals": [],
"source_publication_times": {
"market_published_at": "2026-09-08T11:20:00Z",
"forecast_generated_at": "2026-09-08T11:20:00Z",
"model_variant": "fallback_core"
},
"calculation_time": "2026-09-08T12:30:00Z",
"data_status": "ok",
"tariff_assumptions": { "import_configured": true, "export_configured": true, "...": "..." },
"prices": [
{
"start": "2026-09-08T12:00:00Z",
"end": "2026-09-08T13:00:00Z",
"market_eur_per_kwh": 0.00255,
"import_eur_per_kwh": 0.13813,
"export_eur_per_kwh": -0.01745,
"source": "market"
}
]
}
Hiaten staan in missing_intervals met start,
end en intervals. Wij vullen ze nooit op met een verzonnen
prijs, ook niet om altijd 168 uur te kunnen leveren.
GET /api/v2/charge-plan
Laadplan vanaf nu tot een vertrekdeadline. Van een deels verstreken interval telt alleen de resterende tijd mee. Intervallen zonder prijs bestaan voor de planning niet en worden dus nooit als gratis energie ingepland.
| Parameter | Standaard | Betekenis |
|---|---|---|
departure | verplicht | Vertrekmoment als ISO-8601. Zonder offset als Nederlandse tijd. |
energy_kwh | verplicht | Hoeveel kWh er in de accu moet. |
power_kw | verplicht | Laadvermogen. 1 fase 16A is 3,7 en 3 fasen 16A is 11. |
efficiency | 0.9 | Laadrendement. |
available_from / available_until | null | Lokale uren waarin geladen mag worden. 18 tot 8 loopt over middernacht. |
compare_immediate | true | Reken direct laden als referentie mee. |
Tijdzones rond de klokwisseling
Een lokale tijd zonder offset wordt geweigerd wanneer hij dubbelzinnig is. Op de
laatste zondag van oktober bestaat 02:30 twee keer, en op de laatste zondag van
maart helemaal niet. In beide gevallen krijg je een 422 met het verzoek
een expliciete offset mee te geven.
{
"departure": "2026-09-08T05:00:00Z",
"energy_requested_kwh": 30.0,
"energy_from_grid_kwh": 33.333,
"energy_scheduled_kwh": 33.333,
"energy_shortfall_kwh": 0.0,
"completion_pct": 100.0,
"energy_on_market_prices_kwh": 33.333,
"energy_on_forecast_kwh": 0.0,
"estimated_total_cost_eur": 7.0198,
"cost_is_estimate": false,
"horizon_limited": false,
"feasible": true,
"data_status": "ok",
"valid_until": "2026-09-08T13:30:00Z",
"plan": [
{
"start": "2026-09-08T12:30:00Z",
"end": "2026-09-08T13:00:00Z",
"kwh": 5.5,
"market_eur_per_kwh": 0.00255,
"price_eur_per_kwh": 0.13813,
"cost_eur": 0.7597,
"source": "market",
"cost_is_estimate": false,
"partial_interval": true
}
],
"comparison": { "comparable": true, "reference_cost_eur": 7.4636, "savings_eur": 0.4438, "savings_pct": 5.9 },
"assumptions": { "...": "..." }
}
Onhaalbaar tegenover ongeldig
- Een onhaalbare vraag geeft
200met een gedeeltelijk plan,feasible: false, eenenergy_shortfall_kwhen eennote. - Ongeldige invoer geeft
422. - Ontbrekende data geeft
503, ofdata_statusoppartialwanneer er nog wel iets bruikbaars is.
De vergelijking met direct laden loopt onder dezelfde deadline, vensters, energievraag en tarieven. Hij vervalt wanneer beide varianten niet evenveel energie leveren, en het percentage vervalt bij een referentie van nul of lager.
POST /api/v2/battery-plan
Chronologisch laad-, ontlaad- en bewaarplan. POST en geen GET, omdat er batterijinstellingen en twee optionele tijdreeksen in gaan.
Twee modi
| Modus | Wat er meetelt |
|---|---|
price_only | Alleen prijzen en batterijgegevens. Zonproductie en huishoudverbruik tellen niet mee. Dit is dus geen volledig huishoudelijk energieplan. |
household | Met de meegegeven pv_forecast en load_forecast. Ontbreekt de dekking, dan wordt de horizon zichtbaar ingekort. |
Een ontbrekende prognose wordt nooit als nul productie of nul
verbruik gelezen. Het interval valt dan buiten de horizon, en dat staat in
limitations.
Conventies
| Teken | power_kw en energy_kwh zijn positief bij laden en negatief bij ontladen. |
|---|---|
| Meetpunt | Alle batterijstromen zijn gemeten aan de wisselstroomkant, dus zoals de meter ze ziet. |
| Rendement | Laden: inhoud += ac * charge_efficiency. Ontladen: inhoud -= ac / discharge_efficiency. Verlies telt één keer. |
| Degradatie | degradation_cost_eur_per_kwh rekent over de doorvoer aan batterijzijde. Laden en ontladen tellen allebei mee, dus een volle cyclus van 10 kWh is 20 kWh doorvoer. |
| Energiebalans | verbruik + batterij - zon = netto. Positief is import, negatief is export. Nooit allebei tegelijk. |
Optimalisatiemethode
Dynamisch programmeren over een gediscretiseerde laadstand. Per interval wordt voor elke begin- en eindlaadstand uitgerekend welke batterijstroom nodig is, of dat mag binnen alle grenzen, en wat het kost. Daarna wordt achterwaarts de goedkoopste route gezocht.
Dat is exact optimaal op het gekozen raster, standaard 41 niveaus,
en daarmee benaderend optimaal op het werkelijke continue probleem. Wij claimen dus
geen gegarandeerd optimum. Met soc_levels maak je het raster fijner,
wat preciezer en trager is.
Energie die aan het eind van de horizon in de accu zit telt mee tegen
residual_value_eur_per_kwh. Zonder die post zou het model de batterij
leegtrekken alleen omdat de horizon ophoudt. De standaardwaarde is bewust laag,
namelijk de goedkoopste afnameprijs binnen de horizon maal het ontlaadrendement,
zodat hij dumpen voorkomt zonder hamsteren te belonen.
Verzoek
POST /api/v2/battery-plan
X-API-Key: JOUW_API_KEY
Content-Type: application/json
{
"mode": "household",
"battery": {
"capacity_kwh": 10,
"current_soc_pct": 45,
"soc_measured_at": "2026-09-08T14:28:00+02:00",
"min_soc_pct": 10,
"max_soc_pct": 100,
"max_charge_kw": 3.6,
"max_discharge_kw": 3.6,
"charge_efficiency": 0.95,
"discharge_efficiency": 0.95,
"degradation_cost_eur_per_kwh": 0.02
},
"settings": {
"horizon_hours": 24,
"target_soc_pct": 20,
"allow_grid_charging": false,
"allow_battery_export": false,
"max_import_kw": null,
"max_export_kw": null,
"residual_value_eur_per_kwh": null,
"soc_levels": 41,
"max_soc_age_minutes": 120,
"valid_for_minutes": 60
},
"tariff": {
"supply_surcharge": 0.02,
"energy_tax": 0.09161,
"vat_pct": 21,
"feed_in_deduction": 0.02
},
"pv_forecast": [{ "start": "2026-09-08T13:00:00Z", "kwh": 2.4 }],
"load_forecast": [{ "start": "2026-09-08T13:00:00Z", "kwh": 0.5 }]
}
load_forecast is de totale verwachte huishoudlast
aan de wisselstroomkant, exclusief de batterijstromen zelf. Een auto die je
apart via charge-plan laat plannen hoort er dus wél in, precies
één keer en op de uren waarop dat plan daadwerkelijk laadt. Wat er
niet in hoort is het jaargemiddelde van die auto uitgesmeerd over alle uren,
want dan telt hij dubbel. Beide reeksen mogen maximaal 400 punten hebben.
Antwoord
{
"plan_id": "bp_f199e6c7928302ea",
"mode": "household",
"calculated_at": "2026-09-08T12:30:00Z",
"valid_until": "2026-09-08T13:30:00Z",
"input_data_timestamps": {
"soc_measured_at": "2026-09-08T12:28:00Z",
"soc_age_minutes": 2.0,
"market_published_at": "2026-09-08T11:20:00Z",
"forecast_generated_at": "2026-09-08T11:20:00Z",
"pv_forecast_intervals": 24,
"load_forecast_intervals": 24
},
"horizon_requested": 24,
"horizon_planned": 24,
"horizon_limited": false,
"data_status": "ok",
"feasibility_status": "ok",
"plan": [
{
"start": "2026-09-08T13:00:00Z",
"end": "2026-09-08T14:00:00Z",
"action": "charge",
"power_kw": 1.9,
"energy_kwh": 1.9,
"expected_soc_start_pct": 45.0,
"expected_soc_end_pct": 63.05,
"expected_import_kwh": 0.0,
"expected_export_kwh": 0.0,
"energy_cost_eur": 0.0,
"degradation_cost_eur": 0.0361,
"market_eur_per_kwh": 0.0231,
"price_source": "forecast",
"partial_interval": false
}
],
"summary": {
"energy_cost_eur": -0.0321,
"degradation_cost_eur": 0.3105,
"total_cost_eur": 0.2784,
"grid_import_kwh": 3.6441,
"grid_export_kwh": 7.1368,
"battery_throughput_kwh": 15.525,
"final_soc_pct": 41.5,
"intervals_planned": 24
},
"assumptions": { "...": "..." },
"limitations": []
}
Haalbaarheid
feasibility_status | Betekenis |
|---|---|
ok | Er is een plan dat alle grenzen respecteert. |
infeasible | Binnen de grenzen is geen plan te maken dat de eindlaadstand haalt. De reden staat in limitations. |
no_data | Geen bruikbare prijsintervallen binnen de horizon. |
Wij geven geen besparingsclaim zonder expliciete referentie. Wil je weten wat het
plan oplevert, vergelijk summary.total_cost_eur dan met een eigen
berekening onder dezelfde voorwaarden, bijvoorbeeld door hetzelfde verzoek te
herhalen met een batterij die niets mag doen.
Wat een uitvoerende koppeling moet doen
Deze API levert informatie en plannen. De uitvoering doet je eigen systeem, via de apparaatkoppelingen die je al hebt. Een koppeling die daadwerkelijk stuurt hoort:
- Te controleren of de prijsdata en de laadstand vers genoeg zijn, via
data_status,soc_age_minutesenvalid_until. - Een handmatige override te respecteren.
- Te signaleren wanneer de werkelijkheid van het plan afwijkt.
- Het plan opnieuw op te vragen bij een relevante verandering, bijvoorbeeld een sterk afwijkende laadstand.
- Te voorkomen dat twee regelaars tegelijk sturen. Laat de eigen optimalisatie van je batterij uit staan, of gebruik dit alleen als advies.
Actuele zonneproductie is iets anders dan een prognose. Wil je in real time op
overschot sturen, gebruik dan de meetgegevens uit je eigen systeem en niet
pv_forecast.
Wij leveren zelf geen zonprognose, want wij weten niets van jouw dak. Wie
household gebruikt levert pv_forecast en
load_forecast zelf aan. Ons
Homey-script haalt de zonprognose op bij
Forecast.Solar op basis van coordinaten, hellingshoek, orientatie en piekvermogen, en
laat zien hoe je zoiets zelf inricht.
Er komt geen apart endpoint per conditie. Iets als "netto terugleverprijs is
negatief" leid je af uit export_eur_per_kwh in
/v2/prices.
Aan de slag
Voor Homey staat de volledige route met kant-en-klare scripts in de Homey-handleiding. De v1-endpoints en de Home Assistant-voorbeelden staan op de API-pagina.
Nog geen abonnement? Dat kost 4,99 euro per maand inclusief btw en geeft toegang tot alle endpoints, v1 en v2.