Webhooks — wir melden uns bei Ihnen
Push statt ständig pollen — SpotpriceAPI ruft Ihre URL bei Forecast-/Plan-Updates. Spart Community-Kontingent (200/Tag). Ergänzt Hours Demand und Forecast. Offene REST — jeder HTTP-Client; Loxone meist per Miniserver-HTTP-Out.
Was ist ein Webhook? (Alltag)
Normalerweise fragt Ihr System ständig nach: „Gibt’s was Neues?“ (Polling).
Ein Webhook ist das Gegenteil: Wir rufen Ihre Adresse an, wenn etwas Wichtiges passiert — wie eine SMS „Paket ist da“, statt dass Sie jede Minute beim Paketshop anrufen.
Welche Events gibt es?
| Event | Wann |
|---|---|
forecast.updated | Neue Strompreis-Prognose ist fertig |
plant.plan_updated | Sich der Hours-Ladeplan, O12, O11/charge_power_kw, Hold/Cap, PV-Pack (pv_hash), grid_charge_allowed, Latch/charge_now/charge_stop_soc_pct oder hours_control_paused (Cold-Start / Dual-Cycle Warm-up enter/exit, Engine hours_demand_v1.36) merklich geändert hat — inkl. Near-Min-, Session-Complete-Decide und leerer Tombstone nach Profil-Save |
Beide nutzen dieselbe Webhook-URL und dasselbe Secret aus dem Portal.
Wann nutzen?
- Sie wollen weniger oft die API pollen
- Ihr Server / Miniserver hat eine öffentliche HTTPS-URL, die wir erreichen können
Hinweis für Loxone-Einsteiger: Webhooks sind fortgeschritten (Port-Freigabe / Cloud). Für den Start reichen Timer + Virtual Output (Pull). Guides: Loxone.
Einrichtung (kurz)
1. Im Portal unter Webhook-Einstellungen HTTPS-URL eintragen 2. Secret notieren 3. Eingehende Requests prüfen (Signatur-Header X-Spotforecast-Signature)
Beispiel-Payload plant.plan_updated
{
"event": "plant.plan_updated",
"issued_at": "2026-08-17T18:40:00+02:00",
"hours_needed": 3,
"hours_needed_today": 2,
"energy_charge_kwh": 4,
"charge_hours_today": [
{ "start": "2026-08-17T19:00:00+02:00", "end": "2026-08-17T20:00:00+02:00" }
],
"prefix_hours_needed_today": 2,
"prefix_period_hours_today": 10,
"prefix_energy_charge_kwh": 4,
"charge_now": 1,
"charge_stop_soc_pct": 72,
"charge_latched": false,
"charge_stop_hysteresis_pp": 2.0,
"hours_control_paused": false,
"discharge_power_kw": 9,
"discharge_reason": "recharge_planned",
"adaptive_discharge": true,
"min_soc_pct": 20,
"charge_power_kw": 7.9,
"grid_charge_allowed": true,
"hours_demand_url": "https://api.spotpriceapi.com/v1/decision/hours-demand",
"pv_forecast_url": "https://api.spotpriceapi.com/v1/plant/pv-forecast",
"pv_issued_at": "2026-08-17T16:40:00+00:00",
"pv_hash": "c0ffee12abcd3456",
"plan_hash": "a1b2c3d4e5f67890"
}
Lesen: Heute noch 2 Stunden / 4 kWh Soll; voller Plan 3 Stunden. EMS-Skalare wie Hours Decide (O1/O2/O9/O11–O13). Bei Cold-Start-Mute: charge_now=0, charge_stop_soc_pct: null, hours_control_paused: true. discharge_power_kw (O12) ist volle Cap, außer Surplus-Cap Hold (ab hours_demand_v1.20, live v1.36): Slot-Cap (hold_share \| pack_reserve 0…0,2 \| Weak/cheap_hold≈1 kW) sobald Now ∈ Hold-Set (ohne zweiten Cover-Gate), unter der Kurven-Oberkante mit dem Speicherstand (an oder unter dem Mindeststand 0, auch bei späterer Ladung), oder Wallbox lädt (ev_charge_block / ev_charge_limit). Ladestunden: volle Cap bei aktiver Netzladung nur ab der Kurven-Oberkante (charge_now und nicht latched/grid-aus); darunter die Rampe. Latch/Grid-aus → kein Vollcap, Hold-Cap wenn Now ∈ Hold. Ein Wechsel der O12-Cap, der O11/charge_power_kw (Profil Max. Netzladung / Anschluss), der Hold-Starts oder Hold-Caps (hold_hours inkl. Cap-Vektor (start, discharge_cap_kw)), des PV-Packs (pv_hash) oder von grid_charge_allowed oder hours_control_paused löst ebenfalls plant.plan_updated aus. Nach Profil-Speichern bei Decide-Fail/incomplete: Push mit leeren Charge-Slots + discharge_power_kw=0/charge_now=0 + aktuellem grid_charge_allowed (keine stale Netzladungen/O12 am EMS; sticky charge_latched/charge_stop_soc_pct/charge_stop_hysteresis_pp bleiben, H7; Loxone .bak bleibt bis erfolgreichem VO-Pull). Nach dem Event optional GET /v1/plant/pv-forecast pullen (pv_forecast_url) — Serve-D0 mit PV-Zähler = Ist+Prognose wie Portal/Sparvo (Pack Prefer ≤6 h speichert Modell-FC; bei Weather-Refresh schreibt der Server das Pack auch ohne neuen Webhook nach). Ein PV-Meter-Tick allein ändert Serve-D0, feuert aber kein plant.plan_updated (pv_hash = Pack-FC).
Voller Wochenplan: Das Event enthält nur charge_hours_today (kompakt). Nach jedem plant.plan_updated GET /v1/decision/hours-demand mit mode=decide pullen — Feld day_plan / volle charge_hours / hold_hours. Optional plan_hash (16 Zeichen, SHA-256 der Plan-Starts) zum Dedupe. Materialität prüft intern Today und volle Plan-Starts und Hold-Starts und Hold-Cap-Vektor und O11/charge_power_kw und pv_hash und grid_charge_allowed und charge_now und charge_stop_soc_pct und charge_latched und charge_stop_hysteresis_pp und hours_control_paused (Fingerprint nur nach Push-OK; HTTP-Fail/not_configured → kein Fingerprint, Retry beim nächsten Decide/DA) (morgen-only-, Hold-/Cap-/O11-/PV-, Grid-Gate-, Latch-, H- oder Warm-up-Pause-Änderungen triggern Push). Reine SOC-Korrektur ohne Slot-, O12-, O11-, Hold-, PV-, Grid-Gate-, charge_now-, Latch-, H-, Stopp- oder Pause-Änderung (z. B. Cover-Refine v1.9) löst kein Event aus.
Was Webhooks nicht sind
Webhook ist nicht der Weg, um SOC und Zähler zu uns zu schicken. Dafür: Plant Telemetry oder Hours.
Nächste Schritte
Community registrieren oder Code-Beispiele mit Ihrem persönlichen Key.