Quick start

Hi! This is the API behind the Magdeburg weather site, and you are welcome to use it on yours. Everything is a plain GET that returns JSON. Want German text? Add ?lang=de to any endpoint.

curl https://weather.jroering.com/api/v1/fsi
{
  "score": 8.5,
  "band": "Excellent",
  "band_key": "excellent",
  "color": "#40ad3e",
  "advice": "Perfect suiting conditions. Touch grass and enjoy the festival!",
  "wetbulb_c": 16.8,
  "effective_wetbulb_c": 16.8,
  "subscores": [ … ],
  "meta": { "station_id": "10361", "language": "en", … }
}

This page is the short version. Full schemas live at /docs, and the raw spec is at /openapi.json.

Two rules

Endpoints

EndpointReturnsSize
/api/v1/fsi The index right now: score, band, colour, advice, four sub-scores ~1 kB
/api/v1/current Latest station reading: temperature, wind, pressure, cloud ~0.7 kB
/api/v1/forecast Weather and index, hour by hour. ?hours=1…120, default 24 ~7 kB
/api/v1/daily Per day: min, max and average index, best and worst hour, totals ~3 kB
/api/v1/warnings Official DWD warnings and advance notices in force ~2 kB
/api/v1/scale The band thresholds and their colours ~0.6 kB
/api/v1/overview All of the above in one call, same shapes ~15 kB
/api/health Liveness, plus how old each cached source is ~0.3 kB

Every response carries meta

So you can always tell where the numbers came from:

The Fursuiting Index

The FSI is a 0 to 10 score for how safe and how pleasant it is to be in a fullsuit outdoors. 0 is grim, 10 is perfect. It assumes no cooling vest and no fans, so treat it as a hint rather than a verdict. Four weighted parts feed it, and each one comes back with its own score, weight and a plain reason:

keyWeightWhat it looks at
thermal_humidity50 %Wet-bulb temperature plus sun load. The big one.
precipitation30 %Rain rate blended with the chance of rain, plus wet ground
wind12 %A light breeze is ideal. Still air and gales both hurt.
stickiness8 %Dew point. Above 15 °C the air feels clammy.

It is not just a weighted mean. The score is the lower of that mean and the thermal_humidity and precipitation sub-scores, so neither dangerous heat nor rain can be averaged away: without that, a perfect "it is not raining" would drag a genuinely unsafe hour up into the middle of the scale. When one of the two bites, the score is simply equal to that sub-score.

Switch on band_key, not band

band is translated text and changes with ?lang=. band_key stays put: excellent, good, fair, poor, bad. Colours come from /api/v1/scale, defined once on the server so your charts cannot drift out of step with ours. An hour counts as suitable at or above suitable_from (5.0).

Warnings

Warnings do not change the index. They sit next to it and you decide what to do with them. A warning covers a whole region for hours at a time, so folding it into the score flattened the hour by hour detail the forecast exists to show. The hazards that matter for suiting are already measured per hour in the sub-scores. If you want them combined, do it yourself from /api/v1/warnings.

advance: true marks a Vorabinformation. That is DWD flagging possible severe weather before it is certain enough to warn on, so please do not show it as a warning in force. This site draws it with red diagonal hatching.

headline, description and instruction are DWD's official wording and are always German, whatever lang you ask for. Passing them through untouched is deliberate: translating official safety text is not ours to do. Only label is translated. Use kind and severity for logic.

Rate limit & caching

100 requests per minute per client, on a sliding window. Every response tells you where you stand:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97

Go over and you get a 429 with a Retry-After header and retry_after_seconds in the body. The pages themselves are not limited, so a display board can never lock itself out of its own HTML.

Please cache

The limit is a politeness ceiling, not a challenge. Polling faster buys you nothing, because the upstream data does not move that fast. Every response carries an honest Cache-Control you can just obey.

SourceDWD publishesWe cache
Station observationshourly10 min
MOSMIX point forecastevery ~6 h30 min
Warningsevery few minutes3 min

Once a minute is plenty. This site's own frontend refreshes every five minutes.

Errors

StatusMeaning
422A parameter failed validation, e.g. lang=fr, wind_unit=mps, or hours outside 1…120
429Rate limited. The body has retry_after_seconds
503No usable DWD data at all right now

One source being down is not an error. The JSON endpoints still answer with everything else and name the casualty in meta.degraded. A failed refresh also falls back to the last good value, so you may get slightly stale data rather than none. That is why generated_at and observed_at are worth reading.

Attribution & fair use

All weather data comes from Deutscher Wetterdienst (DWD) and is used under GeoNutzV. If you republish it, credit DWD. The exact string is in meta.attribution of every response.

This is a local weather site for Magdeburg. It is not an official DWD service, and the index is advice, not a safety certification: heat exhaustion is real, and no number replaces your own judgement or a headless break. Please do not lean on it for decisions where being wrong matters.

If you build something with it, that is genuinely welcome. Just cache, and set a User-Agent so a runaway script can be told apart from a person.