Skip to content

API documentation

Jules Dejaeghere edited this page Jan 3, 2025 · 7 revisions

Introduction

This file describes the API used in this repository to get the weather data. The API is not publicly documented and has been reversed engineered using the Android app be.irm.kmi.meteo.

Data available for the following countries: Belgium, The Netherlands and Luxembourg.

Please be mindful if you plan to use this API:

  • This is not a publicly documented API: behavior could change without notice
  • Avoid spamming: this integration refreshes the data every 7 minutes by default
  • Make your client identifiable: this integration uses the following HTTP header User-Agent: github.com/jdejaegh/irm-kmi-ha

Disclaimer

This is a personal project and isn't in any way affiliated with, sponsored or endorsed by The Royal Meteorological Institute of Belgium.

Overview

API endpoint: https://app.meteo.be/services/appv4/

Operations and parameters are passed using a query string. All requests are HTTP GET requests.

Example: GET https://app.meteo.be/services/appv4/?l=fr&s=searchCities&n=Bru

Available operations

method name description
getForecasts Main operation to get current weather as well as hourly and daily forecast
searchCities Search a city to get its city code (used to get forecasts)
getWarnings Get a global list of all warnings, for the three countries
getIncaImage Get precipitation radar image (observation and forecast)
getLocalizationLayer Get image with a dot at the given coordinates (for radar animation)
getSvg Get SVG graph for max temp, min temp and rain for 14-days forecast
getCommunesPerProvince Lists all municipalities in the specified province (why not?)

Common parameters

Not all parameters are used for each method. There are other parameters, but they seem useless (they can be omitted without modifying the output).

parameter name type description example
s string operation to perform (see Available operations) getForecasts
l string language for the response fr
lat float latitude (avoid putting lots of decimals) 51.2213
long float longitude (avoid putting lots of decimals) 4.4051
th string theme modifier (d for day theme, n for night theme) n
rs int other theme modifier 1
ins int city number (different from postal code) 92094
i string date and time 202412301830
k string key to use the service (md5 hex-encoded, changes based on time and method) 53355e94f33c3abba785ecc064a17a55

Compute the key

The key for the parameter k is required for most methods.

The key is generated by MD5 hashing the following values, separated by semicolon: r9EnW374jkJ9acc, method name and today's date (dd/mm/yyyy). The following Python snippet is an example:

import hashlib
hashlib.md5("r9EnW374jkJ9acc;getForecasts;31/12/2024".encode()).hexdigest()

Return values

This section briefly describes what each method returns and how the parameters are used.

As you will notice, some values that are integers or floats are sometimes returned as strings. Keep that in mind when using the values.

getForecasts

Required parameters: s, k, and either lat and long or ins
Optional parameters: l (seems to default to English)

Example: GET https://app.meteo.be/services/appv4/?lat=51.2213&long=4.4051&k=585940aff31585bcfff7f3aa0dc290de&s=getForecasts

Output schema is as follows. Some full examples can be found in the tests/fixtures folder (example)

{
  "cityName": "Antwerp",
  "country": "BE",
  "obs": {},
  "for": {},
  "module": [],
  "animation": [],
  "todayObsCount": 569
}

The keys cityName and country are self-explanatory.
The cityName key is subject to translation according to the l parameter (could have been Anvers or Antwerpen here).

The key todayObsCount indicates how many observations the users of the application submitted today.

Other keys have their own section below

obs key

Give the current weather observation, with temperature (in Celsius) and weather condition.

Example

{
  "temp": 6,
  "timestamp": "2024-12-30T14:50:00+01:00",
  "ww": 15,
  "dayNight": "d"
}

The combination of ww and dayNight (d if the sun is above the horizon, n if below) determines which icon is shown for the weather condition.

Table with icons matching
ww-dayNight icon
0-d
0-n
10-d
10-n
11-d
11-n
12-d
12-n
13-d
13-n
14-d
14-n
15-d
15-n
16-d
16-n
17-d
17-n
18-d
18-n
19-d
19-n
1-d
1-n
20-d
20-n
21-d
21-n
22-d
22-n
23-d
23-n
24-d
24-n
25-d
25-n
26-d
26-n
27-d
27-n
2-d
2-n
3-d
3-n
4-d
4-n
5-d
5-n
6-d
6-n
7-d
7-n
8-d
8-n
9-d
9-n

for key

This key provides information about daily and hourly forecasts, as well as warnings for the current location.

for.daily: list of daily weather forecast (including today)

The list in for.daily is sorted by time: today is the first element of the list. The list may also contain one element for the next (or current) night prevision. It generally contains 7 days of forecast.

Example of list item

{
  "dayName": {"fr": "Lundi", "nl": "Maandag", "en": "Monday", "de": "Montag"},
  "period": "1",
  "day_night": "1",
  "dayNight": "d",
  "text": {
    "nl": "Deze namiddag...",
    "fr": "Cette après-midi..."
  },
  "dawnRiseSeconds": "31500",
  "dawnSetSeconds": "60360",
  "tempMin": null,
  "tempMax": 7,
  "ww1": 15,
  "ww2": null,
  "wwevol": null,
  "ff1": 4,
  "ff2": null,
  "ffevol": null,
  "dd": 45,
  "ddText": {"fr": "SO", "nl": "ZW", "en": "SW", "de": "SW"},
  "wind": {
    "speed": 20,
    "peakSpeed": null,
    "dir": 45,
    "dirText": { "fr": "SO", "nl": "ZW", "en": "SW", "de": "SW"}
  },
  "precipChance": 0,
  "precipQuantity": "0"
}

Note that no matter the language set by the parameter l, all the languages will be present in the output show here.

  • dayName is self-explanatory.
  • period: ?
  • day_night and dayNight: are 1 and d respectively when the forecast is for daytime; are 0 and n respectively when the forecast is for nighttime.
  • text: gives weather forecast in plain language, for Dutch en French only.
  • dawnRiseSeconds and dawnSetSeconds: sunrise and sunset time in seconds after midnight that day.
  • tempMin and tempMax: minimum and maximum temperature. Minimum is null when not relevant anymore (in the today's forecast when it's the afternoon)
  • ww1 and ww2: weather condition, which, in combination with day_night, give the icon to show (see table in obs key section). Two values may be given if the condition is forecasted to change during the day.
  • wwevol: how the condition will evolve between ww1 and ww2. Non null only if ww2 is non null. Values are null or integer, but I did not investigate what they produce in the app.
Example of two weather conditions

In this image, the partly cloudy icon is given by ww1, the rainy icon is given by ww2 and the double arrow is given by wwevol.

  • ff1, ff2 and ffevol: ?
  • dd and wind.dir: wind direction, but WATCH OUT! To get the real direction (where the wind is coming from), you have to do: (dd + 180) mod 360. They use that value to rotate an arrow that defaults to north (when dd=0), hence the trick.
  • ddText and wind.dirText: wind direction (no trick here)
  • wind.speed and wind.peakSpeed: forecasted wind speed and wind gusts speed (if any, might be null), in km/h.
  • precipChance: precipitation probability in percents (between 0 and 100)
  • precipQuantity: forecasted amount of precipitation in mm/m²

for.hourly: list of hourly weather forecast (including current hour)

The list in for.hourly is sorted by time: current hour is the first element of the list.
It generally contains 48 hours of forecast.

Example of list item

{
  "hour": "14",
  "dayNight": "d",
  "temp": 7,
  "ww": "15",
  "precipChance": "0",
  "precipQuantity": 0,
  "pressure": 1028,
  "windSpeedKm": 25,
  "windPeakSpeedKm": null,
  "windDirection": 23,
  "windDirectionText": {"nl": "ZZW", "fr": "SSO", "en": "SSW", "de": "SSW"}
}

Note that no matter the language set by the parameter l, all the languages will be present in the output show here.

  • hour: hour of the day for which the forecast is. This is represented as a zero-padded string ("01" is 1 AM) and there is no indication of the day. The list starts with the current hour, and it is up to the client to keep track of the day.
  • dayNight: d when the forecast is for daytime; n when the forecast is for nighttime.
  • temp: forecasted temperature in Celsius.
  • ww: weather condition, which, in combination with dayNight, give the icon to show (see table in obs key section).
  • precipChance: precipitation probability in percents (between 0 and 100)
  • precipQuantity: forecasted amount of precipitation in mm/m²
  • pressure: atmospheric pressure in hPa.
  • windSpeedKm and windPeakSpeedKm: forecasted wind speed and wind gusts speed (if any, might be null), in km/h.
  • windDirection: wind direction, but WATCH OUT! To get the real direction (where the wind is coming from), you have to do: (windDirection + 180) mod 360. They use that value to rotate an arrow that defaults to north (when windDirection=0), hence the trick.
  • windDirectionText: wind direction (no trick here)

for.warning: list of warnings

List of upcoming and current warnings for the current location.

The for.showWarningTab is true when the list in for.warning is not empty.

Example of list item

{
  "icon_country": "BE",
  "warningType": {
    "id": "2",
    "name": {
      "fr": "Conditions glissantes",
      "nl": "Gladheid",
      "en": "Ice or snow",
      "de": "Glätte"
    }
  },
  "warningLevel": "1",
  "text": {
    "fr": "Ce soir...",
    "nl": "Vanavond, vannacht...",
    "en": "The ground...",
    "de": "Der Boden..."
  },
  "fromTimestamp": "2025-01-03T21:00:00+01:00",
  "toTimestamp": "2025-01-04T10:00:00+01:00"
}

Note that no matter the language set by the parameter l, all the languages will be present in the output show here.

  • icon_country: country code for the warning.
  • warningType.id: id of the warning, see table below for all the known ids.
  • warningType.name: translated names for the warning, see table below for all names.
  • warningLevel: level of the warning from 1 (weak) to 3 (strong).
  • text: translated descriptions for the warning text.
  • fromTimestamp and toTimestamp: timespan of the warning. Note that warnings may appear before the fromTimestamp. They are generally not shown after the toTimestamp.
Table with known warning ids and names

This table may not be exhaustive: it was build by observing the data returned by the API over time. You can open an issue if you find a new id and name.

Warning id Warning name (en, fr, nl, de)
0 Wind, Vent, Wind, Wind
1 Rain, Pluie, Regen, Regen
2 Ice or snow, Chute de neige ou verglas, Sneeuw of ijzel, Glätte
3 Thunder, Orage, Onweer, Gewitter
7 Fog, Brouillard, Mist, Nebel
9 Cold, Froid, Koude, Kalt
12 Thunder Wind Rain, Orage, rafales et averses, Onweer Wind Regen, Gewitter Windböen Regen
13 Thunderstorm & strong gusts, Orage et rafales, Onweer en wind, Gewitter und Windböen
14 Thunderstorm & large rainfall, Orage et averses, Onweer en regen, Gewitter und Regen
15 Storm surge, Marée forte, Stormtij, Sturmflut
17 Coldspell, Vague de froid, Koude, Koude

for.graph: 14-days forecast graphs

This key contains three graphs for the 14-days forecast: maximum temperature, minimum temperature and rainfall. The graphs are always nested under the svg key, which contains a list of objects. Each graph is translated in the four languages.

Here is an example

{
  "svg": [
    {
      "url": {
        "nl": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=tx&l=nl&k=c10e09ed15d26f241cfc056ccac49b5e",
        "fr": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=tx&l=fr&k=c10e09ed15d26f241cfc056ccac49b5e",
        "en": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=tx&l=en&k=c10e09ed15d26f241cfc056ccac49b5e",
        "de": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=tx&l=de&k=c10e09ed15d26f241cfc056ccac49b5e"
      },
      "ratio": 1.3638709677419354
    },
    {
      "url": {
        "nl": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=tn&l=nl&k=c10e09ed15d26f241cfc056ccac49b5e",
        "fr": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=tn&l=fr&k=c10e09ed15d26f241cfc056ccac49b5e",
        "en": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=tn&l=en&k=c10e09ed15d26f241cfc056ccac49b5e",
        "de": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=tn&l=de&k=c10e09ed15d26f241cfc056ccac49b5e"
      },
      "ratio": 1.3638709677419354
    },
    {
      "url": {
        "nl": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=rr&l=nl&k=c10e09ed15d26f241cfc056ccac49b5e",
        "fr": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=rr&l=fr&k=c10e09ed15d26f241cfc056ccac49b5e",
        "en": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=rr&l=en&k=c10e09ed15d26f241cfc056ccac49b5e",
        "de": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=11002&e=rr&l=de&k=c10e09ed15d26f241cfc056ccac49b5e"
      },
      "ratio": 1.3638709677419354
    }
  ]
}

The e query parameter determines the kind of graph:

  • tx for maximum temperature
  • tn for minimum temperature
  • rr for rainfall

I don't know what ratio is used for, maybe display settings.