WattWanneer

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.

EndpointWaarvoor
GET /api/v2/pricesPrijzen vanaf het lopende uur, met je eigen afname- en teruglevertarief. Voor zonnepanelen en energiemanagement.
GET /api/v2/charge-planLaadplan met een vertrekdeadline. Voor elektrisch rijden.
POST /api/v2/battery-planUitvoerbaar 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"
Watv1v2
Limiet per minuut per key1020
Tellereigeneigen, 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

OnderwerpAfspraak
TijdstempelsAltijd UTC met Z. Invoer zonder offset wordt als Nederlandse tijd gelezen.
Intervallenstart inclusief, end exclusief. Bronresolutie is een uur.
PrijzenEUR per kWh.
EnergiekWh. Vermogen in kW. Laadstand in procent van de capaciteit.
KlokwisselingEen lokaal etmaal heeft 23, 24 of 25 uur. Elke berekening gebruikt de werkelijke intervalduur.
Herkomstsource is market voor een gepubliceerde prijs en forecast voor een voorspelling.
Ontbrekende waardenWorden gemeld, nooit stilzwijgend nul.
MomentopnameBinnen één aanvraag werken alle berekeningen op hetzelfde bevroren beeld van de bronnen.

Datastatus

WaardeBetekenis
okVolledige dekking, geen hiaten, verse bron.
partialMinder intervallen dan gevraagd, of hiaten in de reeks.
staleDe nieuwste bron is ouder dan 36 uur, dus er is minstens één pijplijnrun gemist.
unavailableGeen 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)
ParameterEenheidStandaardBetekenis
supply_surchargeEUR/kWhnullInkoopopslag van je leverancier, exclusief btw. Mag negatief.
energy_taxEUR/kWhnullEnergiebelasting exclusief btw. Eerste schijf 2026 is 0.09161.
vat_pctprocentnullBtw over de afnameprijs. In Nederland 21.
feed_in_deductionEUR/kWhnullWat je leverancier inhoudt per teruggeleverde kWh. Negatief als je een toeslag krijgt.
feed_in_floor_pctprocentnullWettelijke ondergrens als percentage van het kale leveringstarief. Vanaf 2027 is dat 50.
feed_in_vat_pctprocentnullBtw over de terugleververgoeding.

Wat er bewust niet in zit

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.

ParameterStandaardBereikBetekenis
fromnowalleen nowStartmoment.
hours1681 tot 192Aantal 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.

ParameterStandaardBetekenis
departureverplichtVertrekmoment als ISO-8601. Zonder offset als Nederlandse tijd.
energy_kwhverplichtHoeveel kWh er in de accu moet.
power_kwverplichtLaadvermogen. 1 fase 16A is 3,7 en 3 fasen 16A is 11.
efficiency0.9Laadrendement.
available_from / available_untilnullLokale uren waarin geladen mag worden. 18 tot 8 loopt over middernacht.
compare_immediatetrueReken 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

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

ModusWat er meetelt
price_onlyAlleen prijzen en batterijgegevens. Zonproductie en huishoudverbruik tellen niet mee. Dit is dus geen volledig huishoudelijk energieplan.
householdMet 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

Tekenpower_kw en energy_kwh zijn positief bij laden en negatief bij ontladen.
MeetpuntAlle batterijstromen zijn gemeten aan de wisselstroomkant, dus zoals de meter ze ziet.
RendementLaden: inhoud += ac * charge_efficiency. Ontladen: inhoud -= ac / discharge_efficiency. Verlies telt één keer.
Degradatiedegradation_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.
Energiebalansverbruik + 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_statusBetekenis
okEr is een plan dat alle grenzen respecteert.
infeasibleBinnen de grenzen is geen plan te maken dat de eindlaadstand haalt. De reden staat in limitations.
no_dataGeen 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:

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.

Neem een WattWanneer-abonnement