{"openapi":"3.1.2","info":{"title":"meteoblue Measurements API","description":"# Overview\nThe meteoblue Quality-Controlled Measurements API provides access to meteorological data that have undergone\nextended internal quality-control (QC) processes. It is a specialised subset of the Measurements API intended\nfor users who require reliable, pre-validated datasets for analysis, model training, or visualisation.\n\n## Key Capabilities\n- Retrieve time-series quality-controlled (QC) data for individual stations or coordinates\n- Retrieve spatially aggregated QC data harmonised across nearby stations (e.g. by geoname ID)\n\n## Quality-Control Process\nAll data in this API are processed using the meteoblue QC system:\n- Sanity checks against physically impossible values\n- Climatological checks against long-term expected ranges\n- Spatial consistency checks using nearby stations or model data\n- Proprietary extended QC developed by meteoblue\n\n## Data Coverage and Availability\nQC data are not available for all stations or all time periods. Coverage depends on data availability and reliability.\nIf a station does not meet QC criteria, aggregated QC values from nearby stations may be returned instead.\n\n## Accounting and Usage\nAccess to this API requires a meteoblue API key and consumes credits.\n\n**Approximate credit usage:**\n- Time-series QC data — 400 credits per value\n- Spatial QC data — 400 credits per aggregated value\n\n## Limitations and Important Notes\n- QC coverage varies by station and time period\n- Station-level QC data may be replaced with spatial aggregates if unavailable\n- QC ensures validated values, but does not guarantee continuous availability or completeness\n\n## Support\nFor assistance or to report issues, contact **support@meteoblue.com**.","version":"v2","x-logo":{"url":"https://static.meteoblue.com/assets/images/logo/meteoblue_logo_v2.0.png","backgroundColor":"hsl(210deg, 40%, 98%)","altText":"meteoblue","href":"https://docs.meteoblue.com/en/weather-apis/introduction/overview"}},"tags":[{"name":"Measurements-API"}],"servers":[{"url":"https://measurements-api.meteoblue.com"}],"security":[{"apikey":[]}],"paths":{"/v2/qc/spatial":{"parameters":[{"name":"field","in":"query","required":true,"schema":{"type":"string","enum":["airTemperature","dewPoint","relativeHumidity","windSpeed","precipitation","totalCloudCover"],"examples":["airTemperature"]},"description":"Measured Variable"},{"name":"geonameid","in":"query","required":true,"schema":{"type":"integer","examples":[2921044],"minimum":0},"description":"A GeonameId of the polygon of interest.\n\nThe GeoNames geographical database contains polygons of different countries and political areas.\nEach polygon in the database has a unique identifier, which can be used in API-queries.\n\nMore information can be found on the [official GeoNames website](https://www.geonames.org/)."},{"name":"time","in":"query","schema":{"type":"string","format":"date-time","examples":["2025-01-28T12:00:00"],"pattern":"(?:18|19|20|21)\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(?:Z)?"},"description":"The timestamp that will be returned in `ISO8601` `UTC` format.\nFormat has to be in `yyyy-MM-ddTHH:00:00`. Default value is latest hour `UTC`."}],"get":{"tags":["Measurements-API"],"summary":"Quality-controlled Values Within a Polygon","description":"Fetch meteoblue quality-controlled measurement data\n(e.g. temperature, wind, humidity) for all stations located\nwithin a geographic region defined by a Geoname ID polygon.","responses":{"200":{"description":"OK","headers":{"MB-Credits-Accounted":{"$ref":"#/components/headers/accounting-header"}},"content":{"application/json":{"schema":{"type":"object","properties":{"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","description":"The name of this column."},"type":{"type":"string","enum":["date","string","float","boolean","integer"],"description":"The data-type of this column."},"values":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"array","items":{"type":"string","format":"date-time"}},{"type":"array","items":{"type":["number","null"]}},{"type":"array","items":{"type":"integer"}}],"description":"The actual values of interest."}},"required":["column","type","values"]}},"rows":{"type":"integer","description":"The amount of rows present in each column."}},"required":["columns","rows"]},"examples":{"Example Spatial":{"summary":"Example Spatial","description":"Example of a Spatial Response with two stations.","value":{"columns":[{"type":"string","column":"id","values":["the_station_id1","the_station_id2"]},{"type":"date","column":"timestamp","values":[1577836800,1577836800]},{"type":"float","column":"lat","values":[47.558399,0.0]},{"type":"float","column":"lon","values":[7.57327,0.0]},{"type":"float","column":"asl","values":[279,null]},{"type":"float","column":"airTemperature","values":[-11.4,-12.1]}],"rows":2}}}}}},"400":{"$ref":"#/components/responses/error-response","description":"Bad Request"},"401":{"$ref":"#/components/responses/error-response","description":"Unauthorized"},"403":{"$ref":"#/components/responses/error-response","description":"Forbidden"},"429":{"$ref":"#/components/responses/error-response","description":"Too Many Requests"},"503":{"$ref":"#/components/responses/error-response","description":"Service Unavailable"}},"x-codeSamples":[{"lang":"JavaScript","source":"fetch(\"https://measurements-api.meteoblue.com/v2/qc/spatial?field=airTemperature&geonameid=2921044&time=2025-01-01&apikey=YOUR_APIKEY\")\n.then(res => res.json())\n.then(console.log);"},{"lang":"Python","source":"import requests\n\nurl = f\"https://measurements-api.meteoblue.com/v2/qc/spatial?field=airTemperature&geonameid=2921044&time=2025-01-01&apikey=YOUR_APIKEY\"\nresponse = requests.get(url)\nprint(response.json())"},{"lang":"Shell","source":"curl \"https://measurements-api.meteoblue.com/v2/qc/spatial?field=airTemperature&geonameid=2921044&time=2025-01-01&apikey=YOUR_APIKEY\""},{"lang":"Java","source":"import java.net.*;\nimport java.io.*;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        String url = \"https://measurements-api.meteoblue.com/v2/qc/spatial?field=airTemperature&geonameid=2921044&time=2025-01-01&apikey=YOUR_APIKEY\";\n        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();\n        conn.setRequestMethod(\"GET\");\n\n        try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {\n            String line;\n            while ((line = in.readLine()) != null) {\n                System.out.println(line);\n            }\n        }\n    }\n}"}]}},"/v2/qc/timeseries":{"parameters":[{"name":"field","in":"query","required":true,"schema":{"type":"string","enum":["airTemperature","dewPoint","relativeHumidity","windSpeed","precipitation","totalCloudCover"],"examples":["airTemperature"]},"description":"Measured Variable"},{"name":"station","in":"query","schema":{"type":"string","description":"A Station Identifier.","minLength":1},"description":"The id of the station to return. Cannot be specified if location (lat, lon) is given."},{"name":"lat","in":"query","schema":{"type":"number","description":"A Latitude value in degrees (WGS 84) between `-90.0` and `90.0`.","examples":[47.5596],"maximum":90.0,"minimum":-90.0},"description":"Latitude of point of interest, in degrees. Cannot be specified if station is given."},{"name":"lon","in":"query","schema":{"type":"number","description":"A Longitude value in degrees (WGS 84) between `-180.0` and `180.0`.","examples":[7.5886],"maximum":180.0,"minimum":-180.0},"description":"Longitude of point of interest, in degrees. Cannot be specified if station is given."},{"name":"timeStart","in":"query","schema":{"type":"string","format":"date-time","examples":["2020-04-01T12:15:00"],"pattern":"(?:18|19|20|21)\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(?:Z)?"},"description":"Lower Bound of the requested time frame, will always come before the end timestamp.\n## Format\n- ISO8601 in `UTC` Timezone.\n- Date format is `yyyy-MM-ddTHH:mm:ss`.\n- Default value current server system time `UTC` 24 hours ago."},{"name":"timeEnd","in":"query","schema":{"type":"string","format":"date-time","examples":["2020-04-01T13:15:00"],"pattern":"(?:18|19|20|21)\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(?:Z)?"},"description":"Upper Bound of the requested time frame, will always come after the start timestamp.\n## Format\n- ISO8601 in `UTC` Timezone.\n- Date format is `yyyy-MM-ddTHH:mm:ss`.\n- Default value current server system time `UTC`."},{"name":"aggregation","in":"query","schema":{"type":"string","enum":["min","max","sum","mean"]},"description":"Aggregation function used to reduce the hourly values to a single value per `resolution` interval, e.g. all 24 hours of a day to one daily value.\n\nMust be specified together with `resolution`; specifying only one of the two results in a `400 Bad Request`.\nIf neither is set, the raw hourly values are returned."},{"name":"resolution","in":"query","schema":{"type":"string","enum":["daily","monthly","yearly"],"examples":["daily"]},"description":"Target resolution of the aggregated values.\nWhen set, the `timestamp` column of the response contains the start of each interval instead of the hourly timestamps.\n\nMust be specified together with `aggregation`; specifying only one of the two results in a `400 Bad Request`."},{"name":"gapFillDomain","in":"query","schema":{"type":"string","examples":["ERA5T","ICON","NEMSGLOBAL"],"minLength":1},"description":"Model used to fill missing values in the station data, e.g. hours where the station did not report a value.\nThe missing values are replaced with the value of the given model for the same location and time.\n\nCan be used on its own. `aggregation` (together with `resolution`) requires `gapFillDomain` to be set;\nspecifying `aggregation` without it results in a `400 Bad Request`."}],"get":{"tags":["Measurements-API"],"summary":"Timeseries of a station","description":"Retrieves a quality-controlled time series for a single station.\nThe data includes timestamps, coordinates and the requested measurement field.\n\n### Query by Station ID or Location\nYou can request data either by:\n- providing a full station query ID (e.g. `METEOSCHWEIZ_BAS`), or\n- using latitude and longitude, in which case the nearest available QC station is automatically selected and no station ID is required.\n\n### Constructing a valid query station id\nRequest a list of available providers using the `/provider/list` endpoint. You may filter providers by a measurement parameter (e.g. airTemperature).\n\nRequest a list of available stations for a specific provider using `/provider/{provider}/station/get`.\n\nConstruct the station ID by combining:\n1. the **capitalised provider name**,\n2. an underscore _, and\n3. the **station ID** returned in the list from the provider. \\\nExample: `PROVIDERNAME_STATIONID` → `METEOSCHWEIZ_BAS`\n\n### Aggregation and Gap Filling\nBy default, the endpoint returns the raw hourly values. The optional parameters `aggregation`, `resolution` and `gapFillDomain` allow transforming the result:\n\n- **Aggregation**: set `aggregation` to reduce the hourly values to a single value per interval. The `timestamp` column then contains the start of each interval.\nBoth parameters need to be specified together, otherwise a `400 Bad Request` is returned.\nAggregation requires `gapFillDomain` to be set, otherwise a `400 Bad Request` is returned.\n- **Gap filling**: set `gapFillDomain` (e.g. `ERA5T`) to fill missing values with data from the given model.\nGap filling can be used on its own, with or without aggregation.\n\n### When to use\nUse this endpoint when you need station-level time series that\nhave already passed meteoblue internal QC checks — ideal for\nanalysis, visualization, or model training. It is the most\ndirect way to retrieve per-station, quality-controlled\nobservations over time.","responses":{"200":{"description":"OK","headers":{"MB-Credits-Accounted":{"$ref":"#/components/headers/accounting-header"}},"content":{"application/json":{"schema":{"type":"object","properties":{"columns":{"type":"array","items":{"type":"object","properties":{"column":{"type":"string","description":"The name of this column."},"type":{"type":"string","enum":["date","string","float","boolean","integer"],"description":"The data-type of this column."},"values":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"array","items":{"type":"string","format":"date-time"}},{"type":"array","items":{"type":["number","null"]}},{"type":"array","items":{"type":"integer"}}],"description":"The actual values of interest."}},"required":["column","type","values"]}},"rows":{"type":"integer","description":"The amount of rows present in each column of this response."}},"required":["columns","rows"]},"examples":{"Example Timeseries":{"summary":"Example Timeseries","description":"Example of a Timeseries Response with two timestamps.","value":{"columns":[{"type":"string","column":"id","values":["the_station_id1","the_station_id1"]},{"type":"date","column":"timestamp","values":[1577836800,1577840400]},{"type":"float","column":"lat","values":[47.558399,47.558399]},{"type":"float","column":"lon","values":[7.57327,7.57327]},{"type":"float","column":"asl","values":[279,279]},{"type":"float","column":"airTemperature","values":[-11.4,-12.1]}],"rows":2}}}}}},"400":{"$ref":"#/components/responses/error-response","description":"Bad Request"},"401":{"$ref":"#/components/responses/error-response","description":"Unauthorized"},"403":{"$ref":"#/components/responses/error-response","description":"Forbidden"},"429":{"$ref":"#/components/responses/error-response","description":"Too Many Requests"},"503":{"$ref":"#/components/responses/error-response","description":"Service Unavailable"}},"x-codeSamples":[{"lang":"JavaScript","source":"fetch(\"https://measurements-api.meteoblue.com/v2/qc/timeseries?field=airTemperature&station=METEOSCHWEIZ_BAS&apikey=YOUR_APIKEY\")\n.then(res => res.json())\n.then(console.log);"},{"lang":"Python","source":"import requests\n\nurl = f\"https://measurements-api.meteoblue.com/v2/qc/timeseries?field=airTemperature&station=METEOSCHWEIZ_BAS&apikey=YOUR_APIKEY\"\nresponse = requests.get(url)\nprint(response.json())"},{"lang":"Shell","source":"curl \"https://measurements-api.meteoblue.com/v2/qc/timeseries?field=airTemperature&station=METEOSCHWEIZ_BAS&apikey=YOUR_APIKEY\""},{"lang":"Java","source":"import java.net.*;\nimport java.io.*;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        String url = \"https://measurements-api.meteoblue.com/v2/qc/timeseries?field=airTemperature&station=METEOSCHWEIZ_BAS&apikey=YOUR_APIKEY\";\n        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();\n        conn.setRequestMethod(\"GET\");\n\n        try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {\n            String line;\n            while ((line = in.readLine()) != null) {\n                System.out.println(line);\n            }\n        }\n    }\n}"}]}}},"components":{"responses":{"error-response":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean","const":true,"description":"Flag indicating that an error has occurred."},"error_message":{"type":"string","description":"Message describing the error."}},"required":["error","error_message"]},"examples":{"Error Message Example":{"summary":"Example Error","description":"Example of a possible error message","value":{"error":true,"error_message":"Message describing the error."}}}}}}},"headers":{"accounting-header":{"schema":{"type":"integer","examples":[0],"minimum":0},"description":"The total number of credits which were accounted from the user of the apikey for the made request."}},"securitySchemes":{"apikey":{"description":"A meteoblue API access key","type":"apiKey","name":"apikey","in":"query"}}}}