{"openapi":"3.1.0","info":{"title":"HND Open Water API","version":"1.0.0","description":"Kostenlose, schlüssellose API. Deutschlandweite Pegelmetadaten und Hochwasserwarnungen; Sachsen-Anhalt ist die Standardansicht, harz bezeichnet ausschließlich den Landkreis Harz. Keine amtliche Warnplattform. Keine vollständige Datenabdeckung. Lizenzbedingungen der jeweiligen Quellen gelten."},"servers":[{"url":"https://api.wasser.waldrand.dev:3001","description":"Öffentliche API-Instanz (API_PUBLIC_URL oder aktueller Ursprung)"}],"paths":{"/health":{"get":{"summary":"API Liveness (keine Upstream-Readiness)","responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"const":"ok"},"service":{"type":"string"},"uptime":{"type":"number"},"storage":{"type":"object","properties":{"kind":{"const":"sqlite"},"schemaVersion":{"type":"integer"},"observations":{"type":"integer","description":"Anzahl gespeicherter Beobachtungen; keine Aussage über aktuelle Quellenverfügbarkeit."},"lastObservationAt":{"type":["string","null"],"format":"date-time"}}}}}}}}}}},"/api/v1/overview":{"get":{"summary":"Gesamtansicht mit expliziter Datenverfügbarkeit","parameters":[{"name":"region","in":"query","required":false,"schema":{"type":"string","enum":["harz","sachsen-anhalt","germany"],"default":"sachsen-anhalt"}}],"responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Snapshot"}}}},"400":{"description":"Ungültige Parameter (INVALID_REQUEST).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpunkt oder Standort unbekannt. Bekannte Pegel ohne Beobachtungen liefern eine leere Zeitreihe mit HTTP 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Ratenlimit überschritten (120/min und Quell-IP). Zeitversetzt erneut versuchen.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Sekunden bis zu einem erneuten Versuch","schema":{"type":"integer"}}}},"500":{"description":"Interner Fehler (INTERNAL_ERROR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/stations":{"get":{"summary":"Pegelstandorte und verfügbare Messwerte","parameters":[{"name":"region","in":"query","required":false,"schema":{"type":"string","enum":["harz","sachsen-anhalt","germany"],"default":"sachsen-anhalt"}},{"name":"search","in":"query","schema":{"type":"string","maxLength":120}}],"responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"type":"object","properties":{"stations":{"type":"array","items":{"$ref":"#/components/schemas/Station"}},"total":{"type":"number"},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderState"}},"generatedAt":{"type":"string"}}}}}},"400":{"description":"Ungültige Parameter (INVALID_REQUEST).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpunkt oder Standort unbekannt. Bekannte Pegel ohne Beobachtungen liefern eine leere Zeitreihe mit HTTP 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Ratenlimit überschritten (120/min und Quell-IP). Zeitversetzt erneut versuchen.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Sekunden bis zu einem erneuten Versuch","schema":{"type":"integer"}}}},"500":{"description":"Interner Fehler (INTERNAL_ERROR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/stations/{id}":{"get":{"summary":"Ein Pegelstandort","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_.-]{1,80}$"}}],"responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Station"}}}},"400":{"description":"Ungültige Parameter (INVALID_REQUEST).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpunkt oder Standort unbekannt. Bekannte Pegel ohne Beobachtungen liefern eine leere Zeitreihe mit HTTP 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Ratenlimit überschritten (120/min und Quell-IP). Zeitversetzt erneut versuchen.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Sekunden bis zu einem erneuten Versuch","schema":{"type":"integer"}}}},"500":{"description":"Interner Fehler (INTERNAL_ERROR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/stations/{id}/history":{"get":{"summary":"Verfügbare Wasserstandsreihe und lokal gesammelte Beobachtungen","description":"Originalzeitreihe, soweit integriert, ergänzt um echte lokal gespeicherte Beobachtungen. Umfang hängt von Quelle und Betriebsdauer ab; keine künstliche Historie. Bekannte Pegel ohne Beobachtungen liefern HTTP 200, measurements: [] und provider.state: unavailable. Nur unbekannte Pegel liefern HTTP 404. Zeitstempel, Einheiten und Providerzustand beachten.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-zA-Z0-9_.-]{1,80}$"}}],"responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"type":"object","properties":{"stationId":{"type":"string"},"parameter":{"const":"W"},"measurements":{"type":"array","items":{"$ref":"#/components/schemas/Measurement"}},"provider":{"$ref":"#/components/schemas/ProviderState"}}}}}},"400":{"description":"Ungültige Parameter (INVALID_REQUEST).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpunkt oder Standort unbekannt. Bekannte Pegel ohne Beobachtungen liefern eine leere Zeitreihe mit HTTP 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Ratenlimit überschritten (120/min und Quell-IP). Zeitversetzt erneut versuchen.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Sekunden bis zu einem erneuten Versuch","schema":{"type":"integer"}}}},"500":{"description":"Interner Fehler (INTERNAL_ERROR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/warnings":{"get":{"summary":"LHP-Hochwasserwarnungen via NINA","parameters":[{"name":"region","in":"query","required":false,"schema":{"type":"string","enum":["harz","sachsen-anhalt","germany"],"default":"sachsen-anhalt"}}],"responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"type":"object","properties":{"warnings":{"type":"array","items":{"$ref":"#/components/schemas/Warning"}},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderState"}},"generatedAt":{"type":"string"}}}}}},"400":{"description":"Ungültige Parameter (INVALID_REQUEST).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpunkt oder Standort unbekannt. Bekannte Pegel ohne Beobachtungen liefern eine leere Zeitreihe mit HTTP 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Ratenlimit überschritten (120/min und Quell-IP). Zeitversetzt erneut versuchen.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Sekunden bis zu einem erneuten Versuch","schema":{"type":"integer"}}}},"500":{"description":"Interner Fehler (INTERNAL_ERROR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/forecast":{"get":{"summary":"72-Stunden-Niederschlagsprognose und modellierter täglicher GloFAS-Abfluss","description":"Open-Meteo-Modellprognosen an ausgewählten Orten. Die Niederschlagseinschätzung ist eine transparente Heuristik und keine amtliche Hochwasserwarnung. GloFAS-Tageswerte sind Modellwerte und keine Pegelmessungen; grobe Modellauflösung kann von lokalen Gewässern abweichen. Providerzustände und Vollständigkeit beachten.","parameters":[{"name":"region","in":"query","required":false,"schema":{"type":"string","enum":["harz","sachsen-anhalt","germany"],"default":"sachsen-anhalt"}}],"responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForecastSnapshot"}}}},"400":{"description":"Ungültige Parameter (INVALID_REQUEST).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpunkt oder Standort unbekannt. Bekannte Pegel ohne Beobachtungen liefern eine leere Zeitreihe mit HTTP 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Ratenlimit überschritten (120/min und Quell-IP). Zeitversetzt erneut versuchen.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Sekunden bis zu einem erneuten Versuch","schema":{"type":"integer"}}}},"500":{"description":"Interner Fehler (INTERNAL_ERROR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/rivers":{"get":{"summary":"Regional gefilterte Flüsse; vollständige schematische Verläufe","parameters":[{"name":"region","in":"query","required":false,"schema":{"type":"string","enum":["harz","sachsen-anhalt","germany"],"default":"sachsen-anhalt"}}],"responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"type":"object","properties":{"rivers":{"type":"array","items":{"$ref":"#/components/schemas/River"}}}}}}}}}},"/api/v1/reservoirs":{"get":{"summary":"Regional gefilterte Talsperren mit verfügbaren Betreiber-Messwerten","description":"telemetry enthält ausschließlich tatsächlich verfügbare Betriebsdaten. Bauliche capacityMillionM3 und aktueller Stauinhalt sind unterschiedliche Größen. Fehlende Felder bedeuten unbekannte Werte, nicht null Kubikmeter oder Entwarnung.","parameters":[{"name":"region","in":"query","required":false,"schema":{"type":"string","enum":["harz","sachsen-anhalt","germany"],"default":"sachsen-anhalt"}}],"responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"type":"object","properties":{"reservoirs":{"type":"array","items":{"$ref":"#/components/schemas/Reservoir"}},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderState"}},"generatedAt":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Ungültige Parameter (INVALID_REQUEST).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Endpunkt oder Standort unbekannt. Bekannte Pegel ohne Beobachtungen liefern eine leere Zeitreihe mit HTTP 200.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Ratenlimit überschritten (120/min und Quell-IP). Zeitversetzt erneut versuchen.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Sekunden bis zu einem erneuten Versuch","schema":{"type":"integer"}}}},"500":{"description":"Interner Fehler (INTERNAL_ERROR).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sources":{"get":{"summary":"Quellenverzeichnis","responses":{"200":{"description":"OK. Providerzustände beachten: HTTP 200 garantiert keine aktuellen Quelldaten.","content":{"application/json":{"schema":{"type":"object","properties":{"sources":{"type":"array","items":{"$ref":"#/components/schemas/Source"}}}}}}}}}}},"components":{"schemas":{"ForecastLocation":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"district":{"type":"string"}}},"ForecastHour":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"precipitationMm":{"type":["number","null"]},"rainMm":{"type":["number","null"]},"probabilityPercent":{"type":["number","null"]}}},"RainfallForecast":{"type":"object","properties":{"location":{"$ref":"#/components/schemas/ForecastLocation"},"hourly":{"type":"array","items":{"$ref":"#/components/schemas/ForecastHour"}},"totals":{"type":"object","properties":{"next24hMm":{"type":["number","null"]},"next72hMm":{"type":["number","null"]},"max1hMm":{"type":["number","null"]},"max6hMm":{"type":["number","null"]}}},"rainfallClass":{"type":"string","enum":["low","elevated","high","unknown"]},"completeness":{"type":"string","enum":["complete","partial","unavailable"]},"explanation":{"type":"string"}}},"RiverForecast":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"water":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"model":{"type":"string"},"daily":{"type":"array","items":{"type":"object","properties":{"timestamp":{"type":"string"},"dischargeM3s":{"type":["number","null"]}}}},"note":{"type":"string"}}},"ForecastSnapshot":{"type":"object","properties":{"generatedAt":{"type":"string","format":"date-time"},"region":{"type":"string","enum":["harz","sachsen-anhalt","germany"]},"horizonHours":{"const":72},"locations":{"type":"array","items":{"$ref":"#/components/schemas/RainfallForecast"}},"riverForecasts":{"type":"array","items":{"$ref":"#/components/schemas/RiverForecast"}},"provider":{"$ref":"#/components/schemas/ProviderState"},"riverProvider":{"$ref":"#/components/schemas/ProviderState"},"methodology":{"type":"object","properties":{"version":{"type":"string"},"description":{"type":"string"},"thresholds":{"type":"string"},"limitations":{"type":"array","items":{"type":"string"}},"sources":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"}}}}}}}},"Measurement":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"value":{"type":"number"},"unit":{"type":"string"}},"required":["timestamp","value","unit"]},"ProviderState":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"state":{"type":"string","enum":["live","cached","unavailable","reference"]},"fetchedAt":{"type":["string","null"],"format":"date-time"},"stale":{"type":"boolean"},"dataUpdatedAt":{"type":"string","format":"date-time"},"message":{"type":"string"},"url":{"type":"string"}},"required":["id","name","state","fetchedAt","message","url"]},"Station":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"water":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"agency":{"type":"string"},"sourceUrl":{"type":"string"},"region":{"type":"string"},"measurement":{"anyOf":[{"$ref":"#/components/schemas/Measurement"},{"type":"null"}]},"discharge":{"anyOf":[{"$ref":"#/components/schemas/Measurement"},{"type":"null"}]},"freshness":{"type":"string","enum":["current","stale","unavailable"]},"note":{"type":"string"},"warningLevel":{"type":"integer","minimum":-1,"maximum":4},"warningLabel":{"type":"string"},"warningSource":{"type":"string"},"warningTimestamp":{"type":"string"},"historyAvailable":{"type":"boolean","description":"Eine integrierte Originalreihe oder echte lokal gespeicherte Beobachtungen sind verfügbar."},"measurementSourceId":{"type":"string","description":"Quellstations-ID für den zugeordneten Messwert und seine Originalzeitreihe, z. B. eine PEGELONLINE-UUID; nicht automatisch Quelle der Warnklasse."},"sourceStationNumber":{"type":"string","description":"Unveränderte Original-Pegelnummer der Quelle."}},"required":["id","name","water","latitude","longitude","agency","sourceUrl","region","measurement","discharge","freshness"]},"Warning":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"severity":{"type":"string","enum":["extreme","severe","moderate","minor","unknown"]},"source":{"type":"string"},"sourceUrl":{"type":"string"},"sentAt":{"type":"string"},"expiresAt":{"type":["string","null"]},"area":{"type":"string"},"region":{"type":"string"},"instruction":{"type":"string"}},"required":["id","title","severity","source","sourceUrl","sentAt","expiresAt","area","region"]},"GeoPoint":{"type":"object","properties":{"name":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"}},"required":["name","lat","lon"]},"River":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"lengthKm":{"type":"number"},"researchVerified":{"type":"boolean"},"basin":{"type":"string"},"region":{"type":"array","items":{"type":"string"}},"source":{"$ref":"#/components/schemas/GeoPoint"},"mouth":{"$ref":"#/components/schemas/GeoPoint"},"route":{"type":"array","items":{"$ref":"#/components/schemas/GeoPoint"}},"reservoirIds":{"type":"array","items":{"type":"string"}},"sourceIds":{"type":"array","items":{"type":"string"}},"description":{"type":"string"},"geometryAccuracy":{"const":"approximate"}}},"Reservoir":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"capacityMillionM3":{"type":"number"},"verifiedFields":{"type":"array","items":{"type":"string","enum":["name","operator","capacityMillionM3"]}},"verifiedAt":{"type":"string","format":"date"},"researchVerified":{"type":"boolean"},"riverId":{"type":"string"},"type":{"type":"string"},"operator":{"type":"string"},"region":{"type":"array","items":{"type":"string"}},"lat":{"type":"number"},"lon":{"type":"number"},"sourceIds":{"type":"array","items":{"type":"string"}},"description":{"type":"string"},"geometryAccuracy":{"const":"approximate"},"telemetry":{"$ref":"#/components/schemas/ReservoirTelemetry"}}},"ReservoirTelemetry":{"type":"object","properties":{"storage":{"$ref":"#/components/schemas/Measurement","description":"Beobachteter Stauinhalt in Mio. m³; keine bauliche Kapazität."},"level":{"$ref":"#/components/schemas/Measurement","description":"Beobachteter Wasserstand in der Originaleinheit der Betreiberquelle."},"inflow":{"$ref":"#/components/schemas/Measurement","description":"Zufluss in m³/s."},"outflow":{"$ref":"#/components/schemas/Measurement","description":"Abgabe in m³/s."},"fillPercent":{"$ref":"#/components/schemas/Measurement","description":"Füllanteil in %, nur bei belegter Bezugsgröße; keine Hochwasserklasse."},"freshness":{"type":"string","enum":["current","stale","unavailable"]},"sourceUrl":{"type":"string","format":"uri"},"sourceName":{"type":"string"},"note":{"type":"string"}},"required":["freshness","sourceUrl","sourceName"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]},"Source":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"operator":{"type":"string"},"url":{"type":"string"},"kind":{"type":"string"},"coverage":{"type":"array","items":{"type":"string"}},"access":{"type":"string"},"researchVerified":{"type":"boolean"},"verifiedAt":{"type":"string","format":"date"}}},"Snapshot":{"type":"object","properties":{"generatedAt":{"type":"string"},"region":{"type":"string","enum":["harz","sachsen-anhalt","germany"]},"stations":{"type":"array","items":{"$ref":"#/components/schemas/Station"}},"rivers":{"type":"array","items":{"$ref":"#/components/schemas/River"}},"reservoirs":{"type":"array","items":{"$ref":"#/components/schemas/Reservoir"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/Warning"}},"sources":{"type":"array","items":{"$ref":"#/components/schemas/Source"}},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderState"}},"coverage":{"type":"object","properties":{"stations":{"type":"string"},"warnings":{"type":"string"},"geography":{"type":"string"},"complete":{"const":false}}}}}}}}