## Infosnow Public Widget V2 (vor Deployment)

GET `/v1/public/infosnow/widget-v2.php` mit `widget=light-ride` ohne API-Key. Vertrag: `infosnow_public_widget_v2`, freigegebene Planned Days mit Zeitfenstern und `validUntil`. `statusRemarks=null`; kein operativer Live-Status und keine Durchfuehrungsbestaetigung. Andere Slugs 404; invalide Parameter 400; Source-Freshness-Luecke 503; Rate-Limit 429. Nochmalige Source-/Rights-Freigabe fuer weitere Objekte zwingend. Kein automatischer Production-Cutover.

# Lenzerheide API Reference

Diese Dokumentation richtet sich an Partner:innen, die freigegebene Daten von W.O.W. Lenzerheide über die API beziehen.

Produktive API-Basis:

```txt
https://api.lenzerheide.swiss
```

Interaktive Swagger-Doku:

```txt
https://docs.lenzerheide.swiss
```

Getrennte OpenAPI-Spezifikationen:

```txt
https://docs.lenzerheide.swiss/openapi-partner.json
https://docs.lenzerheide.swiss/openapi-public.json
```

## Start

Die Dokumentation trennt bewusst zwei API-Bereiche:

| Bereich | Zugriff | Swagger Spec | Zweck |
|---|---|---|---|
| Public API | ohne API-Key | `openapi-public.json` | öffentlich freigegebene Informationen |
| Partner API | API-Key + Scope | `openapi-partner.json` | freigegebene Partnerdaten |

Im Swagger-Dropdown kann zwischen **Partner API · API-Key** und **Public API · ohne API-Key** gewechselt werden.

Die frühere kombinierte Spezifikation `openapi.json` ist Legacy. Verbindlich sind `openapi-public.json` und `openapi-partner.json`.

## Authentifizierung

Public-Endpunkte benötigen keinen API-Key.

Partner-Endpunkte benötigen einen API-Key.

Empfohlener Header:

```txt
X-API-Key: YOUR_API_KEY
```

Alternative:

```txt
Authorization: Bearer YOUR_API_KEY
```

## Scopes

| Scope | Beschreibung |
|---|---|
| `traffic:read` | Zugriff auf freigegebene Partner-Verkehrsdaten |
| `weather:read` | Zugriff auf freigegebene Partner-Wetterdaten |

Fehlt ein benötigter Scope, antwortet die API mit `403 Forbidden`.

## Infosnow LIGHT RIDE – geplante Zeitfenster

GET `/v1/public/infosnow/planned-schedule.php` mit `widget=light-ride` (ohne API-Key). Nur freigegebene LIGHT-RIDE-Planzeiten; keine Durchführungsbestätigung oder Echtzeit-Status. Bei veralteter/fehlender Full-Import-Beobachtung: HTTP 503; unbekannte Widgets: HTTP 404. `sourceDate` bleibt unbekannt (`null`), `validUntil` begrenzt die Import-Freshness. Public-Readback erst nach manuellem Deploy.

## Public API

### API Root

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/` | keine |

```bash
curl "https://api.lenzerheide.swiss/"
```

### API Status

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/status.php` | keine |

```bash
curl "https://api.lenzerheide.swiss/v1/status.php"
```

### Public Destination Context

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/public/destination/context.php` | keine |

Kanalneutrales Data Product fuer **Bergbahnen-Betriebszeiten, Wetter-Tagesforecast und Verkehr**. Es enthaelt keine detaillierten Infosnow-Aktivitaetsgruppen, Parkplatzbelegung, Events oder Kampagneninhalte.

Optionale Query-Parameter: `date=YYYY-MM-DD`, `area=lenzerheide`, `lang=de|en`. Ohne Datum gilt der aktuelle Tag in `Europe/Zurich`.

Die Antwort enthaelt `data.status=complete|partial`, `data.operations`, `data.weather`, `data.mobility.traffic` und die `data.sources`-Evidenz. Consumer beachten pro Modul `available` und `applicable` und pro Quelle `freshness` sowie `observedAt`. Verkehr ist nur fuer den heutigen Tag relevant. HTTP `503` wird geliefert, wenn kein Modul verfuegbar ist.

```bash
curl "https://api.lenzerheide.swiss/v1/public/destination/context.php?area=lenzerheide&lang=de"
```

Weitere Details: `/destination-context-api.md` und `/edge-extension-integration.md`.

### Public Traffic Status

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/public/traffic/status.php` | keine |

```bash
curl "https://api.lenzerheide.swiss/v1/public/traffic/status.php"
```

Optionaler Parameter `max_age_minutes`: 1 bis 240 Minuten, Standard 120. Der Server begrenzt abweichende Zahlenwerte auf diesen Bereich. Ohne aktuelle, zulaessige Verkehrsbeobachtungen antwortet die API mit **503** (kein Nachweis fuer freie Strassen).

### Public Weather Daily

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/public/weather/current.php` | keine |

Der Pfad `current.php` bleibt aus Kompatibilitätsgründen bestehen. Fachlich liefert der Endpunkt den **kanonischen Wetter-Tageswert für das angefragte Datum**. Seit 18. August 2026 ist MeteoSwiss OGD Local Forecast für Punkt `707800` / Lenzerheide/Lai die produktive Weather Source of Truth.

Wichtig: Der produktive Tageswert ist ein Forecast-Wert und **keine Echtzeit-Stationsmessung**. Das wird neu explizit über `dataType=forecast` und `isForecast=true` ausgewiesen.

Optionale Parameter:

| Parameter | Beispiel | Beschreibung |
|---|---|---|
| `date` | `2026-08-18` | Datum im Format `YYYY-MM-DD` |
| `location_key` | `lenzerheide` | aktuell einziger dokumentierter und produktiv verifizierter Standortschlüssel |

Neue Provenance-Felder:

| Feld | Bedeutung |
|---|---|
| `dataType` | `forecast`, `observation` oder `unknown` |
| `isForecast` | explizites Forecast-Kennzeichen |
| `source` | aktuell `meteoswiss` |
| `sourceProduct` | aktuell `meteoswiss-local-forecast` |
| `sourceCreatedAt` | MeteoSwiss Source-Referenz im Format `YYYYMMDDHHMM` |
| `capturedAt` | Zeitpunkt der Erfassung/Aktualisierung im Data Layer |
| `observedAt` | Legacy-Alias für `capturedAt`; keine Stationsmesszeit |

Der MeteoSwiss Daily Forecast liefert aktuell Tal-Minimum, Tal-Maximum, Niederschlag und Wettercode. Nicht gelieferte Legacy-Felder wie Bergtemperaturen, `sunshineHours` und `windGustsKmh` bleiben `null`. Sie werden nicht künstlich ergänzt. Der W.O.W.-Weather Score wird deterministisch nur aus den verfügbaren Tagesfeldern berechnet.

```bash
curl "https://api.lenzerheide.swiss/v1/public/weather/current.php?location_key=lenzerheide"
```

### Public Weather Forecast

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/public/weather/forecast.php` | keine |

Der Endpunkt liefert bis zu sieben Wettertage ab dem aktuellen lokalen Datum aus dem kanonischen MeteoSwiss OGD Local Forecast. Consumer greifen nicht direkt auf MeteoSwiss oder Supabase zu.

Optionale Parameter:

| Parameter | Beispiel | Beschreibung |
|---|---|---|
| `days` | `7` | Anzahl Tage von `1` bis `7`, Standard `7` |
| `location_key` | `lenzerheide` | aktuell einziger dokumentierter und produktiv verifizierter Standortschlüssel |

Auf Collection-Ebene werden `source` und `sourceProduct` ausgegeben. Pro Tag werden `dataType`, `isForecast`, `sourceCreatedAt`, `capturedAt` und der Legacy-Alias `observedAt` mitgeführt.

Auch hier gilt: Bergtemperaturen, `sunshineHours` und `windGustsKmh` bleiben im aktuellen Daily Source Product `null`. Zusätzliche Hourly-Werte wie Niederschlagswahrscheinlichkeit, Wind, Böen, Bewölkung oder Nullgradgrenze sind ein separates internes Data Product und werden nicht stillschweigend in die Public Daily API gemischt.

```bash
curl "https://api.lenzerheide.swiss/v1/public/weather/forecast.php?days=7&location_key=lenzerheide"
```

### Public Weather Hourly

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/public/weather/hourly.php` | keine |

Der Endpunkt liefert einen reduzierten **zukuenftigen Stundenverlauf** aus dem kanonischen MeteoSwiss Hourly Forecast fuer Lenzerheide/Lai. Er gibt keine Rohpayloads, internen Quality-Felder oder Datenbankdetails aus.

Optionale Parameter:

| Parameter | Beispiel | Beschreibung |
|---|---|---|
| `hours` | `12` | exakt `6`, `12`, `18` oder `24`; Standard `12` |
| `location_key` | `lenzerheide` | aktuell einziger dokumentierter und produktiv verifizierter Standortschluessel |

Pro Stunde werden `validAt`, Temperatur, Niederschlagsmenge, Niederschlagswahrscheinlichkeit und Boeen ausgegeben. `sourceCreatedAt` macht die MeteoSwiss-Prognoseversion nachvollziehbar.

```bash
curl "https://api.lenzerheide.swiss/v1/public/weather/hourly.php?hours=12&location_key=lenzerheide"
```

### Public Cross-country Wax Tip

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/public/cross-country/wax.php` | keine |

Der Endpunkt liefert eine **wetterbasierte Gleitwachs-Orientierung fuer heute**. Grundlage sind die verbleibenden MeteoSwiss-Hourly-Werte des lokalen Kalendertags in `Europe/Zurich`.

V1 waehlt keine Marke, Farbe oder Produktfamilie. `recommendedRangeC` ist der nach aussen auf ganze Grad gerundete Lufttemperaturkorridor. Consumer sollen ein Gleitwachs empfehlen, dessen Hersteller-Temperaturbereich diesen Korridor abdeckt.

Explizite Grenzen:

- nur Gleitwachs;
- Lufttemperatur ist nicht Schneetemperatur;
- Schneeart ist nicht verfuegbar;
- keine Steigwachs- oder Klisterempfehlung fuer Classic-Wachsski;
- bei weniger als zwei nutzbaren verbleibenden Stundenwerten: `available=false`.

```bash
curl "https://api.lenzerheide.swiss/v1/public/cross-country/wax.php?location_key=lenzerheide"
```

### Public Lift Status Current

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/public/lifts/current.php` | keine |

Der Endpunkt liefert den reduzierten Near-Live-Betriebsstatus der Infosnow-Anlagen für Lenzerheide. Die Sommer- oder Wintersaison wird anhand des lokalen Datums in `Europe/Zurich` bestimmt.

Der Anlagenkatalog wird saisonübergreifend aus Sommer- und Winterstammdaten zusammengeführt. Nur Anlagen mit einem frischen Live-Wert aus der aktuellen Saison erhalten einen operativen Status. Anlagen ohne aktuellen Live-Wert werden mit `status=unknown` ausgegeben.

Pro Anlage wird zusätzlich `typeId` ausgegeben. Der Wert entspricht der von Infosnow gelieferten `TypID`/`TypeID`. Fehlt eine Typ-ID, ist `typeId` `null`.

Normalisierte Statuswerte:

| Status | Bedeutung |
|---|---|
| `open` | geöffnet |
| `preparing` | in Vorbereitung |
| `closed` | geschlossen |
| `unknown` | kein verlässlicher aktueller Live-Status verfügbar |

Infosnow-Werte, deren Beobachtungszeitpunkt mehr als fünf Minuten zurückliegt, werden nicht als aktueller Live-Status ausgegeben. Der Status wird auf `unknown` gesetzt und `freshness` auf `stale`.

```bash
curl "https://api.lenzerheide.swiss/v1/public/lifts/current.php"
```

### Public Lift Operating Hours

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/public/lifts/operating-hours.php` | keine |

Datumsbezogene Bergbahn-Betriebszeiten mit `hasScheduleData`, `plannedOpen`, `times`, `firstAscent`, `lastAscent`, `lastDescent`, `status` und `statusFreshness` pro Anlage. Optionales `date=YYYY-MM-DD`, Standard heute in `Europe/Zurich`.

Vergangenheit wird aus der historisierten Infosnow-Periode, heute und Zukunft aus dem aktuellen Infosnow-Fahrplan gelesen. **Nur fuer heute** gibt es einen aktuellen Near-Live-Status. `plannedOpen=null` bedeutet unbekannt und ist nicht «geschlossen».

```bash
curl "https://api.lenzerheide.swiss/v1/public/lifts/operating-hours.php"
```

### Public Lift Operating Period History

| Methode | Endpunkt | Auth |
|---|---|---|
| GET | `/v1/public/lifts/periods.php` | keine |

Der Endpunkt liefert ausschliesslich **vollständig vergangene** Infosnow-Betriebsperioden aus der bereits vorhandenen Data-Layer-Historie. Er ist für Gästeinformationen wie die Betriebszeiten-Matrix gedacht, wenn Infosnow eine abgelaufene Periode im aktuellen XML nicht mehr mitliefert.

Pflichtparameter:

| Parameter | Beispiel | Beschreibung |
|---|---|---|
| `season` | `summer` | `summer` oder `winter` |

Wichtig:

- heutige und zukünftige Perioden werden nie aus der Historie ausgegeben;
- aktuelles Infosnow bleibt Source of Truth für heute und Zukunft;
- der Endpunkt gibt keine Infosnow-Rohpayloads, Statushistorie oder internen Beobachtungszeitpunkte aus;
- `coverageFrom` kennzeichnet die früheste valide First-Seen-Provenienz der Historie; fehlt sie, ist der Wert `null` (nicht leerer Text);
- der bereits bestehende Regionsumfang umfasst Infosnow-Resort **57 (Lenzerheide)** und **67 (Arosa)**; Consumer muessen `region` beachten und nicht beide Regionen ungeprueft zusammenzaehlen;
- pro Periode werden `from`, `to`, `days`, reguläre `times` sowie `uphillOnly` und `downhillOnly` ausgegeben.

```bash
curl "https://api.lenzerheide.swiss/v1/public/lifts/periods.php?season=summer"
```

## Partner API

### Partner Traffic Summary

| Methode | Endpunkt | Auth | Scope |
|---|---|---|---|
| GET | `/v1/partner/traffic/summary.php` | API-Key | `traffic:read` |

```bash
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://api.lenzerheide.swiss/v1/partner/traffic/summary.php"
```

Optionaler Parameter `max_age_minutes`: 1 bis 360 Minuten, Standard 120. Ohne aktuelle, zulaessige Verkehrsbeobachtungen antwortet der Endpunkt mit **503**.

### Partner Weather Daily Summary

| Methode | Endpunkt | Auth | Scope |
|---|---|---|---|
| GET | `/v1/partner/weather/summary.php` | API-Key | `weather:read` |

Der Partner-Endpunkt nutzt dieselbe kanonische MeteoSwiss-Tagesbasis wie die Public API. Er übernimmt die expliziten Felder `dataType`, `isForecast`, `source`, `sourceProduct`, `sourceCreatedAt` und `capturedAt`. Bestehende Detailfelder bleiben aus Kompatibilitätsgründen erhalten; nicht vom MeteoSwiss Daily Forecast gelieferte Werte sind `null`.

Optionale Parameter:

| Parameter | Beispiel | Beschreibung |
|---|---|---|
| `date` | `2026-08-18` | Datum im Format `YYYY-MM-DD` |
| `location_key` | `lenzerheide` | aktuell einziger dokumentierter und produktiv verifizierter Standortschlüssel |

```bash
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://api.lenzerheide.swiss/v1/partner/weather/summary.php?location_key=lenzerheide"
```

## Response-Format

Erfolgreiche Antworten folgen grundsätzlich dieser Struktur:

```json
{
  "meta": {
    "apiVersion": "v1",
    "generatedAt": "2026-08-18T15:00:00+02:00",
    "source": "lenzerheide_data_layer",
    "visibility": "partner",
    "module": "traffic"
  },
  "data": {}
}
```

## Fehlercodes

| HTTP Status | Bedeutung | Typische Ursache |
|---:|---|---|
| 200 | OK | Request erfolgreich |
| 400 | Bad Request | ungültige oder fehlende Parameter |
| 401 | Unauthorized | API-Key fehlt oder ist ungültig |
| 403 | Forbidden | API-Key hat keinen passenden Scope |
| 404 | Not Found | Endpunkt existiert nicht |
| 429 | Too Many Requests | Rate Limit erreicht |
| 500 | Server Error | unerwarteter Serverfehler |
| 503 | Service Unavailable | Datenquelle oder Service temporär nicht verfügbar |

## Rate Limits

| Zugriff | Limit |
|---|---:|
| Public API | Standard 120 Requests/Minute und 20 000/Tag pro IP-Adresse |
| Partner API | Standard 60 Requests/Minute und 5 000/Tag pro API-Key |

Die Rate Limits gelten bei aktivierter Limiter-Konfiguration; produktive Private-Settings koennen die Standardwerte ueberschreiben. Die Origin beeinflusst die CORS-Freigabe, nicht den Public-Rate-Limit-Zaehler.

## Nutzungshinweise

- API-Keys nie im Frontend, in Mobile Apps oder öffentlichen Repositories speichern.
- Partner-Endpunkte serverseitig aufrufen.
- Nur notwendige Scopes freigeben.
- Responses cachen, sofern Aktualität und Zweck passen.
- Bei `429` und `503` eine kontrollierte Retry-Logik verwenden.
- Neue Felder können innerhalb von `/v1` ergänzt werden. Integrationen sollten unbekannte Felder ignorieren können.
- `observedAt` bei Weather nicht als Messzeit interpretieren. Für neue Integrationen `capturedAt` und `sourceCreatedAt` verwenden.

## Changelog

Änderungen an Endpunkten, Feldern und Versionen werden hier dokumentiert:

```txt
https://docs.lenzerheide.swiss/api-changelog.md
```