---
title: "Season snowfall ledger for a resort"
method: GET
path: "/api/v1/resorts/{slug}/snowfall-history"
tags: ["Resorts"]
---

# Season snowfall ledger for a resort

`GET /api/v1/resorts/{slug}/snowfall-history`

## Request

- Base URL: `https://www.snowsure.ai`
- URL: `https://www.snowsure.ai/api/v1/resorts/{slug}/snowfall-history`
- Auth: none declared

Every day it snowed this season and how much, in up to three lanes that are **never blended**: `modeled` (ERA5 / Open-Meteo at mid-mountain, 30 winters deep), `measured` (one named station, chosen by truth tier then coverage — never an average of stations), and `reported` (what the resort itself published, including its own season counter). Plus `normal` — the mean cumulative modeled snowfall by day of season across every complete winter on file, with p25/p75 — and a strip of past seasons for sparklines.

`vsNormalPct` exists **only on the modeled lane**, against a modeled normal. A resort-reported total is measured at a summit stake and compares to the resort's own stated annual average, never to this normal. Lanes with nothing observed are absent, not zero.

The modeled lane is sparse at the source (only snow days are stored); the response densifies it, so an absent day is 0 cm. Station lanes keep gaps as `null`. The normal is withheld under `meta.minYearsForNorm` complete winters, with the reason in `meta.normalWithheldReason`.

This is **history, not a forecast**, and nothing in it is a SnowSure Score. A real resort with nothing recorded returns **200** with a modeled lane of zeros, not 404.

## Path parameters

- `slug` string, required

## Query parameters

- `season` string
- `granularity` 'day' | 'week' | 'month'
- `pastSeasons` integer

## Response `200`

The ledger. Lanes present only where something was observed; `data.normal` null when withheld.

- ResortSnowfallHistoryResponse: Season snowfall ledger for one resort: daily snowfall in independent lanes, the normal-to-date curve, and past-season summaries.
  - `schemaVersion` '1.4.0': Versions this payload contract, independently of info.version.
  - `meta` object
    - `source` 'SnowSure'
    - `slug` string: Canonical resort slug, after alias resolution
    - `generatedAt` string, date-time
    - `hemisphere` 'NH' | 'SH'
    - `season` object: The season record window (NH 1 Sep → 30 Jun, SH 1 Jun → 30 Nov) and the ski-month focus window a chart should open on.
      - `year` integer: NH: the calendar year the season starts in. SH: the calendar year.
      - `label` string
      - `start` string, date
      - `end` string, date
      - `focusStart` string, date
      - `focusEnd` string, date
      - `inProgress` boolean
      - `asOf` string, date: Last date the lanes can carry data — yesterday during the season (the modeled lane is mirrored the morning after).
      - `operating` object, nullable: The resort's own season: opening and closing dates for this season_year from resort_seasons, a permanent per-season record. A date in the future is 'scheduled' whatever column it came from.
        - `open` string, date, nullable
        - `close` string, date, nullable
        - `openKind` 'actual' | 'scheduled' | 'null', nullable
        - `closeKind` 'actual' | 'scheduled' | 'null', nullable
        - `source` string, nullable: Provenance of the record: resort_website, manual, sync-resorts-trigger, wikipedia-extraction, …
    - `granularity` 'day' | 'week' | 'month'
    - `seasonsAvailable` object[]: Every season the ledger can be asked for, newest first — the same list whichever season is selected, so a picker never strands the reader in the past.
      - `year` integer
      - `label` string
    - `minYearsForNorm` integer: Complete winters required before `data.normal` is published.
    - `normalWithheldReason` string, nullable: Why `data.normal` is null, when it is.
    - `lanesNote` string: The blending rule, restated for agents that read the payload without the docs.
  - `data` object
    - `lanes` object[]: Independent sources, in order modeled → measured → analysed → reported. A lane with nothing observed is absent. `analysed` is NOAA's National Snowfall Analysis sampled at the resort's coordinates (CONUS only, SS-W-370): a grid cell, not a station, and never blended into `measured`.
      - `key` 'modeled' | 'measured' | 'analysed' | 'reported'
      - `label` string
      - `source` string: Named network or origin — "ERA5 / Open-Meteo", "SNOTEL", "SLF IMIS", "Resort".
      - `sourceKey` string: The snowfall_actuals source key behind the lane.
      - `stationId` string, nullable
      - `stationName` string, nullable
      - `stationElevationM` number, nullable
      - `stationDistanceKm` number, nullable
      - `tier` integer: ML truth tier (1 best). snotel 1, meteofrance 2, resort_reported 3, ghcn/amedas/geosphere 4, depth-derived 5, open_meteo 6.
      - `firstDate` string, date, nullable
      - `lastDate` string, date, nullable
      - `toDateCm` number, nullable: Cumulative through `meta.season.asOf`. Null before the season starts.
      - `toDateSource` 'counter' | 'days' | 'null', nullable: Where `toDateCm` came from. 'counter' is the resort's own published season-to-date figure; 'days' is the sum of this lane's own days. Null when the lane has no total. Never absent — a total without a source is not publishable.
      - `vsNormalPct` integer, nullable: Modeled lane only: signed percent vs `data.normal` at the as-of day. Null on other lanes, when the normal is withheld, or while the normal-to-date is under 10 cm.
      - `days` object[]
        - `date` string, date
        - `cm` number, nullable: Snowfall that day. Null = no observation (station and reported lanes only).
        - `cumCm` number: Cumulative through this day; gaps carry the previous total.
      - `bins` object[]: `days` rolled up to the requested granularity.
        - `start` string, date
        - `end` string, date
        - `cm` number
        - `cumCm` number
        - `observedDays` integer
    - `snowDaysByLane` object: Snow days (≥ 1 cm) per lane, computed once server-side (SS-W-324). Headline and comparison both read `modeled`. A missing lane is 0.
      - `modeled` integer, required
      - `measured` integer, required
      - `analysed` integer, required
      - `reported` integer, required
    - `normal` object, nullable: Normal-to-date from the modeled lane across complete winters. Null when withheld — see `meta.normalWithheldReason`.
      - `winters` integer
      - `days` object[]
        - `dayOfSeason` integer
        - `date` string, date
        - `meanCumCm` number
        - `p25CumCm` number, nullable
        - `p75CumCm` number, nullable
    - `snowsureSeasonCounter` object, nullable: SnowSure's own count of the resort's daily statements this season, stored on the season record every six hours (SS-W-122). Same sum as the reported lane's toDateCm, but persisted. Null until the resort has stated a 24h figure this season.
      - `cm` number
      - `days` integer: Daily statements behind the count, published zeros included.
      - `asOf` string, date, nullable
    - `reportedSeasonCounter` object, nullable: The resort's own published season-to-date total, as last archived. Independent of the reported lane's daily sum.
      - `cm` number
      - `asOf` string, date
    - `depth` object: Snow depth by source and elevation tier, one series each, never blended. A day without a reading is null and drawn as a gap. Lanes absent when nothing was archived.
      - `lanes` object[]
        - `key` 'modeled' | 'reported' | 'measured'
        - `tier` 'base' | 'mid' | 'summit' | 'station'
        - `label` string
        - `source` string: "ERA5 / Open-Meteo", "Resort (website)", "Resort (portal)", or the station network.
        - `stationId` string, nullable
        - `stationName` string, nullable
        - `stationElevationM` number, nullable
        - `observedDays` integer
        - `latest` object, nullable
          - `date` string, date
          - `cm` number
        - `days` object[]
          - `date` string, date
          - `cm` number, nullable
    - `pastSeasons` object[]: Prior seasons, newest first, for the sparkline strip.
      - `seasonYear` integer
      - `label` string
      - `totalCm` number, nullable
      - `snowDays` integer, nullable
      - `maxStormCm` number, nullable
      - `weeklyCumCm` number[]: Modeled cumulative at the end of each 7-day bin from the record start.
      - `reportedTotalCm` number, nullable: What the resort stated that season, summed by SnowSure. Null for seasons before the reported lane existed.
      - `reportedDays` integer, nullable

## Other responses

- `404`: No such resort (after alias resolution). Terminal — do not retry.
- `503`: Resort existence or history could not be read because a backing store was unreachable. Retryable — never used to mean "unknown resort".

---

[API](https://skmtc.dev/snowsure/apis/snowsure-api.md) · [All operations](https://skmtc.dev/snowsure/apis/snowsure-api/llms.txt) · [OpenAPI document](https://skmtc.dev/snowsure/apis/snowsure-api/revisions/dcbcdbb3df50?raw)
