Snow readiness / Setup guide

Setup guide for municipalities

The snow-readiness API tells a municipality how likely snow is to disrupt it in the next 48 hours, 2 to 7 days and 7 to 15 days, as a level from 0 to 3 with a suggested action. It is read-only and free during the pilot winter 2026/27. Every API call needs a key, which you request here.

Decision support only. MET Norway and the other national met services remain the warning authority, and every response links their warnings. The pilot runs in Oslo as an uncalibrated shadow run.

1. Getting access

Request a key with the request form (Norwegian and English). It asks for your country and municipality number, the municipality name, who is asking, your preferred national forecast provider, what you will use the levels for, how you will connect (JSON API, CAP feed or the page) and, if you have them, the points to watch.

  1. Request. Send the form. We read every request ourselves.
  2. Key. If approved, we email you a key of the form sr_<id>_<secret>. It is shown once when issued and only a hash is stored, so keep it in your secret store. Lost keys are revoked and replaced, never recovered.
  3. Points and thresholds. We agree the points with you (centre, nearest snow-measuring station, steep bus or road sections) and any thresholds that differ from the defaults.
  4. Shadow run. We add your municipality; your id is the country code plus the municipality number, for example NO-4601. Your page and API data appear after the first forecast run.
  5. Connect. JSON API, CAP feed, or the page on a wall screen. One key per system is easiest to manage; ask for more if you need them.

Your key works for every municipality in the service, not only your own. A preferred provider other than MET Norway is noted for later: today the 0 to 48 h horizon uses MET Norway's MEPS where it covers you, and ECMWF elsewhere.

What we log. Each API call is stored with your key id, the endpoint, the municipality, the time, the response status and the response time, so we can see how the service is used and plan capacity. We do not store IP addresses. Usage records are deleted after 90 days. Contact details from the form are kept while your key is active; ask us to delete them at any time.

2. Quick start

Base URL: https://snow.benefelds.lv. Send your key as Authorization: Bearer <key> or X-API-Key: <key>. Your municipality id is the ISO country code plus the national municipality number, for example NO-0301 for Oslo.

Find your municipality, its points and thresholds:

export SNOWREADY_KEY=sr_xxxxxxxx_your-secret
curl -H "Authorization: Bearer $SNOWREADY_KEY" https://snow.benefelds.lv/v1/municipalities

Get today's readiness level for each horizon:

curl -H "Authorization: Bearer $SNOWREADY_KEY" https://snow.benefelds.lv/v1/readiness/NO-0301

Check that the data behind it is fresh:

curl -H "Authorization: Bearer $SNOWREADY_KEY" https://snow.benefelds.lv/v1/status

To see the same data without code, open the city page: /m/NO-0301 (add ?lang=nb or ?lang=en). The page, the public freshness summary at /status and the interactive API reference at /docs need no key. Without a key, /v1 answers 401 with a pointer to /join.

3. Readiness levels

Each horizon gets one level from 0 to 3 and one machine-readable action code. The API sends codes, not prose; English and Norwegian Bokmål texts are published at /strings/en.json and /strings/nb.json.

LevelName0 to 48 h action code2 to 7 days action code7 to 15 days action code
0Normalnonenonenone
1Watchbrief_contractorscheck_stock_contractsprepare_season_start
2Standbystandby_prewet_transit_plancontractors_standby_tyre_reminder(not used)
3Actdispatch_reroute_inform(not used)(not used)
Action codeSuggested action
brief_contractorsBrief contractors and check salt stock.
standby_prewet_transit_planContractors on call, pre-wet salt, bus diversion plan ready.
dispatch_reroute_informDispatch ploughs and salt, reroute buses off steep streets, inform the public.
check_stock_contractsCheck salt stock and contractor availability.
contractors_standby_tyre_reminderPut contractors on standby, send the winter-tyre reminder.
prepare_season_startPrepare to declare the season start and switch the fleet to winter tyres.
no_dataNo fresh forecast for this horizon; check /v1/status.

The 7 to 15 day horizon never goes above Watch: at that range ensembles show the weather regime, not a specific event. An official snow or ice warning from the met service in force for the area sets the 0 to 48 h level to 3, whatever the probabilities say.

4. Endpoints

All endpoints are GET, return JSON unless noted, and need your API key. The machine-readable OpenAPI description is at /openapi.json.

EndpointReturnsCall it
/v1/municipalitiesEvery municipality: id, name, country, time zone, points with height in metres, thresholds in force, season stateOnce a day
/v1/readiness/{id}Level, action code, driving event, probability and threshold per horizon; rules that fired; official warnings; season stateEvery 15 min
/v1/forecast/{id}Probability time series per event and source, raw and calibrated side by side. ?by_point=true gives every point instead of the highestEvery 30 to 60 min, for charts
/v1/statusFreshness per upstream source, runs in the last 24 h, degraded flagBefore acting on a level, or every 15 min for monitoring
/v1/cap/{id}.xml0 to 48 h readiness as a CAP 1.2 alert in the national language and English. ?lang=en gives one languageEvery 15 min, or from your CAP aggregator
/m/{id}The city page (HTML, no key), prints to one A4 pageFor people

Errors use plain HTTP status codes: 401 for a missing, unknown or revoked key, 404 for an unknown municipality id, 503 when no readiness has been computed yet (a new municipality before its first run). Coming in Phase 1: /v1/readiness/{id}/history (past levels with what happened), /v1/verification/{id} (hit and false-alarm rates) and webhooks that call your system when a level changes.

5. The readiness response

GET /v1/readiness/{id} is the call most integrations need. Times are UTC ISO 8601, probabilities are 0 to 1, heights are metres.

FieldMeaning
computed_atWhen the levels were last computed
season_state.statepre_first_snow (thresholds × 2/3) or in_season; source says whether it was observed, set for the municipality (override) or the default
first_snow_withinProbability of the season's first snow (≥ 2 cm in 24 h) within 3, 7 and 14 days
official_warnings[]Snow and ice warnings from the met service in force for the area: title, level, link
horizons[].horizonh0_48h, h2_7d or h7_15d
horizons[].level0 to 3
horizons[].actionAction code (see Readiness levels)
horizons[].driving_eventThe event behind the level, or official_warning
horizons[].driving_pointThe point where that event is most likely, for example NO-0301:grefsenkollveien
horizons[].probability / thresholdThe driving event's probability and the threshold it crossed
horizons[].sourceForecast used: meps (0 to 48 h, 2.5 km) or ecmwf_ens (longer range, or fallback)
horizons[].model_run_time / data_age_hThe forecast's start time and its age in hours when computed
horizons[].official_warning_activeWhether an official snow or ice warning is in force
horizons[].rules_fired[]Every rule that held: event, window, probability, threshold, point
horizons[].events[]All event probabilities for the horizon: calibrated p, raw member fraction raw, members, reliability
standby_thresholdsThresholds in force for Standby, for colouring charts
attribution, noticeLicences of the data used, and the decision-support notice with a link to official warnings

Live example for Oslo on 12 November 2026, shortened to the 0 to 48 h horizon and one entry per list:

{
  "municipality_id": "NO-0301",
  "computed_at": "2026-11-12T12:00:23Z",
  "season_state": {"state": "pre_first_snow", "since": "2026-09-01", "source": "default"},
  "first_snow_within": {"3d": 1.0, "7d": 1.0, "14d": 1.0},
  "official_warnings": [{"title": "Snow, yellow level, Large parts of Akershus, Oslo, ...", "awareness_level": "2; yellow; Moderate", "url": "https://www.met.no/..."}],
  "horizons": [{
    "horizon": "h0_48h",
    "level": 3,
    "action": "dispatch_reroute_inform",
    "driving_event": "snow_6h",
    "driving_point": "NO-0301:grefsenkollveien",
    "probability": 0.4333,
    "threshold": 0.4,
    "source": "meps",
    "model_run_time": "2026-11-12T09:00:00Z",
    "data_age_h": 3.0,
    "official_warning_active": true,
    "rules_fired": [{"event": "snow_6h", "level": 3, "window": "0-24h", "p": 0.4333, "threshold": 0.4, "point": "NO-0301:grefsenkollveien"}],
    "events": [{"event": "phase_risk", "window": "0-48h", "p": 0.633, "raw": 0.633, "members": 30, "reliability": "uncalibrated", "point": "NO-0301:grefsenkollveien"}]
  }],
  "standby_thresholds": {"snow_6h": 0.2, "snow_24h_day": 0.2667},
  "notice": {"code": "decision_support_uncalibrated", "official_warnings_url": "https://www.met.no/vaer-og-klima/Ekstremvaervarsler-og-andre-farevarsler"}
}

In plain words: 13 of 30 forecasts give at least 3 cm in 6 hours at Grefsenkollveien within a day, which crosses the lowered pre-season threshold of 0.40, and MET Norway's yellow snow warning is in force, so the level is 3.

6. Events and thresholds

A probability is the share of ensemble forecasts ("members") in which the event happens. For a horizon it is the share of members in which the event happens at least once in that window, at the municipality point where it is highest. Thresholds are per municipality; the values below are Oslo's.

Event codeDefinition (Oslo)Used for
snow_6hAt least 3 cm of new snow in 6 hours0 to 48 h
snow_24hAt least 5 cm of new snow in 24 hoursAll horizons
first_snowAt least 2 cm of new snow in 24 hours, counted only before the season's first snow2 to 15 days
phase_riskAt least 0.5 mm/h of precipitation while the temperature is between −1 and +1.5 °C0 to 48 h
freeze_after_wetRain, then the temperature falls below 0 °C within 6 hours0 to 48 h

Snow depth is computed the same way for every forecast source: temperature is moved to each point's real height (6.5 °C per km), precipitation is split into rain and snow between 0 and +2 °C, and water becomes snow at 10:1 below −2 °C and 7:1 above.

Default rules (a level is reached when any of its rules holds):

HorizonLevelRule
0 to 48 h3 ActP(snow_6h in the next 24 h) ≥ 0.60, or an official snow/ice warning is in force
0 to 48 h2 StandbyP(snow_6h in the next 24 h) ≥ 0.30, or P(snow_24h) ≥ 0.40
0 to 48 h1 WatchP(snow_24h) ≥ 0.15, or P(phase_risk) ≥ 0.30, or P(freeze_after_wet) ≥ 0.30
2 to 7 days2 StandbyP(snow_24h) ≥ 0.40
2 to 7 days1 WatchP(snow_24h) ≥ 0.15, or P(first_snow) ≥ 0.30 before first snow
7 to 15 days1 WatchP(snow_24h) ≥ 0.30, or P(first_snow) ≥ 0.40 before first snow

Before the season's first snow every probability threshold is multiplied by 2/3, because the first snow does the most damage. The season resets on 1 September. The season_state field says which applies.

7. CAP feed

If your operations centre already ingests CAP (Common Alerting Protocol) warnings, point it at GET /v1/cap/{id}.xml and no code is needed. Each alert carries one <info> block in the national language (nb-NO for Norway) and one in English, with the level and action code as <parameter> values for routing rules.

CAP elementValue
statusExercise throughout the pilot, so no system treats it as a live alert; Actual from Phase 1
severityLevel 0 to 2: Minor; level 3: Moderate. Never higher, so it never outranks the met service's own warnings
urgencyLevel 0: Unknown, 1: Future, 2: Expected, 3: Immediate
certaintyLikely when the driving probability is 0.5 or more, else Possible
parameter readiness_level0 to 3
parameter action_codeThe 0 to 48 h action code
webThe municipality's city page

The alert covers the 0 to 48 h horizon only. Use the JSON endpoint for the longer horizons. Many CAP readers cannot set headers; for those, put the key in the address: /v1/cap/NO-0301.xml?api_key=<your key>, and treat that address as a secret.

8. Polling, caching and freshness

Polling every 15 minutes is enough: levels can only change when new data arrives on this schedule (UTC).

DataUpdated
Official warnings (MetAlerts)Every 15 min
MEPS forecast (0 to 61 h)Checked every 30 min; a new run lands about every 3 h
ECMWF ensemble (to 15 days)Checked hourly; new runs four times a day
Observations (season state)Hourly, once the pilot's station feed is connected

Every JSON response has an ETag and Cache-Control: max-age=300 (60 s for /v1/status). Send the ETag back as If-None-Match and an unchanged answer costs a 304 with no body:

curl -H "Authorization: Bearer $SNOWREADY_KEY" -H 'If-None-Match: "8215c486fd84359904e4a69c6ef5ab43"' \
  https://snow.benefelds.lv/v1/readiness/NO-0301

Before acting on a level, check data_age_h in the response or /v1/status. A source is flagged degraded when its last success is older than: MEPS 12 h, ECMWF 24 h, warnings 45 min, observations 3 h. When MEPS is stale the 0 to 48 h horizon falls back to ECMWF and says so in source; when nothing is fresh the action is no_data. The first request after a quiet spell can take a few seconds while the service wakes; later requests are fast.

9. Data sources and liability

SourceUsed forLicence
MET Norway MEPS ensemble: 30 members, 2.5 km, to about 61 h0 to 48 hCC BY 4.0
ECMWF IFS and AIFS ensembles via Open-Meteo: 51 + 51 members, to 15 days2 to 15 days; fallback for 0 to 48 hCC BY 4.0
MET Norway MetAlertsOfficial warningsCC BY 4.0
MET Norway FrostStation observations, season stateCC BY 4.0
Kartverket terrain modelHeight of each pointCC BY 4.0

If you republish our numbers, keep the attribution list from the response with them.

This is decision support, not a warning service. The national met service issues official warnings, and every response and the CAP feed link them. Probabilities in the pilot are raw ensemble shares, not yet calibrated against what actually happened. Treat a level as a prompt to look, not an order to act.

10. Adding your municipality

Adding a municipality is a configuration change, not new code. It is live after its first forecast run, within an hour. The request form covers the first two items; the rest we settle together:

Oslo's points are first candidates and still need confirming against Ruter's network: Holmenkollveien, Grefsenkollveien, Ekebergveien, Lambertseter, Romsås and Tonsenhagen, with Rådhuset and Blindern.