Glossary

A reference for the domain concepts and project-specific terms used throughout luftqualitaet-cli. The underlying API is German (Umweltbundesamt); this glossary gives the term used in the CLI/client alongside the original German where one exists.

Translation table (from the API). The CLI follows these:

German English / API term
Luftqualität air quality
Komponente / Schadstoff component / pollutant
Messnetz network
Messumfang / Scope scope
Station / Messstation station
Stationstyp station type
Stationseinstellung station setting
Überschreitung transgression / exceedance
Jahresbilanz annual balance
Grenzwert / Schwellenwert threshold
Messwert measure / measurement
Stundenwert hourly value

The data source

Umweltbundesamt (UBA). The German Federal Environment Agency (umweltbundesamt.de). It collects and publishes the official German air-quality data this tool wraps.

Air Data API. The UBA’s open, key-free REST API for air-quality data. This client targets the live API path /api/air-data/v3 on https://luftdaten.umweltbundesamt.de (the default base URL; the older address https://www.umweltbundesamt.de/api/air_data/v3 answers with a permanent redirect there). --base-url (the client’s baseUrl) takes the host only — the client adds the API path, and refuses a base URL that already ends in it. It supersedes the v2 OpenAPI spec published at luftqualitaet.api.bund.dev.

Index + data structure. The shape of most API responses: an indices array names the columns (the row layout), and the payload is a compact map keyed by id/code/timestamp rather than an array of labelled objects. The client returns these payloads faithfully as raw JSON (JsonObject / AirDataResult) rather than guessing a strict per-endpoint type, because the layout varies by endpoint and parameters.


Resources / endpoints

The client surfaces two kinds of endpoint: data endpoints (measurements and aggregations for a station/window or component/year) and reference endpoints (the lookup lists that give meaning to the numeric ids).

airquality (/airquality/json). Air-quality index data for one station over a time window. The index has five levels, 0 (very good) to 4 (very poor). CLI: airquality.

airquality-limits (/airquality/limits). The available date range per station for air-quality data — use it to discover what windows you can request. CLI: airquality-limits.

measures (/measures/json). Raw measurement data for a station over a window, for one component and one scope: the response holds one series (one value per hour), so without component/scope the API picks one rather than returning all. The client (and so the CLI) requires both. An id the station doesn’t measure gives "data": {}. CLI: measures.

measures-limits (/measures/limits). The available date range per scope/component/station for measurements. CLI: measures-limits.

annual-balances (/annualbalances/json). Annual tabulations (Jahresbilanzen) for a component and a given year (>= 2016). Each row is a station id followed by figures whose number and meaning depend on the component (for O₃ there is no annual mean); the response’s headers object names them by row position, and its indices array does not match the rows. UBA evaluates them from the final, checked data (“auf Basis der endgültigen Daten”), published in June of the following year; until then the year has no rows. This is the authoritative yearly exceedance count, and it agrees with the stations’ own daily means. CLI: annual-balances.

transgressions (/transgressions/json). Exceedance (Überschreitungen) data for a component and year — how often a limit value was exceeded. The response’s headers object says what the yearly count measures (hours or days above which value); day_recent shows how far the year’s data reaches. UBA offers these tables for the running year (“für das laufende Jahr”), built from preliminary data; a completed year’s table is not brought up to the final data, so its yearly count differs from annual-balances at 10–35 % of PM₁₀ stations in 2019–2025, in both directions (Halle/Paracelsusstr., PM₁₀ 2024: 17 days here, 8 in the annual balance and in the station’s daily means). Use it for the running year and its monthly breakdown; for a completed year rank on annual-balances. CLI: transgressions (with a note, an INFO record, on stderr for a completed year).

thresholds (/thresholds/json). The limit/threshold values for a given use (airquality or measure), optionally per component and scope. CLI: thresholds.

meta (/meta/json). Combined metadata for a use — bundles components, scopes, networks, stations, etc. needed to build other queries. CLI: meta.

Reference lists

components (/components/json). The measured components (pollutants): e.g. PM10, NO₂, O₃, SO₂, CO. CLI: components. Each row carries an id, a code and the unit of measurement.

networks (/networks/json). The measurement networks (Messnetze) — the federal-state and federal monitoring networks that operate the stations. CLI: networks.

scopes (/scopes/json). The measurement scopes (Messumfänge) — the aggregation/averaging definition of a measurement (e.g. hourly average, 24-hour average, the averaging time + the component it applies to). CLI: scopes.

station-types (/stationtypes/json). The station-type classification (e.g. background, traffic, industrial). CLI: station-types.

station-settings (/stationsettings/json). The station-setting classification describing a station’s surroundings (e.g. urban, suburban, rural). CLI: station-settings.

transgression-types (/transgressiontypes/json). The catalogue of exceedance types referenced by the transgressions data. CLI: transgression-types.


Key identifiers & query parameters

station. The numeric station id identifying a monitoring station. A required parameter of airquality and measures. Station ids are 1-based, so the CLI rejects 0 locally. Discover ids via meta / airquality-limits / measures-limits. An id the API doesn’t know mostly gets "data": {} with HTTP 200, like a window without data (only ids far outside the catalogue get HTTP 409); the CLI then looks the id up in the station catalogue (meta --use measure) and exits 4 (not found) when it isn’t there, or prints the empty answer with a note (an INFO record) on stderr when it is.

component. The numeric component id identifying a pollutant. Required by annual-balances / transgressions / measures; optional on thresholds. Resolve the id ↔ pollutant mapping via components.

scope. The numeric scope id identifying a measurement scope (averaging definition). Required by measures, optional on thresholds. Resolve via scopes.

year. A four-digit year for the annual aggregations; the API’s earliest year is 2016, so the CLI rejects anything below that. transgressions is complete only from 2019: for 2016–2018 the API answers some components (NO₂, PM₁₀) with HTTP 500, which the CLI reports with a hint.

Time window (date_from / time_from / date_to / time_to). The data endpoints address a window by a start date+hour and an end date+hour. Dates are YYYY-MM-DD. Hours are hour-ending values in the range 1..24 (not 0..23): hour 1 is the interval ending at 01:00, hour 24 ends at midnight. Times are CET (UTC+1) all year, as the airquality response labels them, so in summer they are one hour behind German local time. The CLI validates the calendar date, the hour range, and rejects a reversed window (start after end) before any request is sent.


Enums / codes surfaced by the client

These are the closed value sets the client validates against (defined in packages/client/src/enums.ts):

lang (Lang). Response language for the labels in reference lists and metadata: de | en. CLI: --lang.

index (IndexKind). How a reference list is keyed in the response: id (the numeric id) | code (the short code). CLI: --index. annual-balances and transgressions accept it too, but their rows are arrays led by the station id, so it changes nothing there.

use (meta) (MetaUse). Which metadata bundle the meta endpoint returns: airquality | measure | transgression | annualbalance | map. When use=airquality, a time window (--date-from + --date-to) is required. For the other uses the window is optional, but the API applies it too (use=measure then lists only the stations active in it), so the client checks it the same way: both dates or neither, hours only with dates, omitted hours sent as 1/24 (DEFAULT_META_TIME_FROM/DEFAULT_META_TIME_TO; the API would otherwise use the current hour), no reversed window. CLI: meta --use.

use (thresholds) (ThresholdUse). Which threshold set the thresholds endpoint returns: airquality | measure. CLI: thresholds --use.


Search & API concepts

Retry / backoff. The API rate-limits and can return transient 429 / 503 responses; the engine retries those automatically, backing off linearly (200 ms, 400 ms, …) or waiting the response’s Retry-After (seconds or an HTTP date) when that is longer — a Retry-After of 0 or a past date never makes it retry sooner. A Retry-After above 30 s is not retried: the error surfaces at once and names the wait the server asked for (--max-retries, 0..10, default 2). A connection the server resets mid-request is retried the same way (linear backoff); a refused connection, a DNS failure or a timeout is not.

Redirects. The engine follows up to 5 HTTP redirects by default (configurable with --max-redirects; 0 disables following). On a cross-origin redirect it strips request headers (re-adding only the benign Accept / User-Agent) so nothing sensitive leaks to a different origin. Credentials in --base-url (https://user:pw@mirror/) go out as an Authorization: Basic header, to the base URL’s own origin (scheme, host, port) only: a same-origin redirect keeps them, relative or absolute, a cross-origin one drops them, and a 401/403 after such a drop says so (an http→https redirect: use an https base URL). Userinfo in a server’s Location is never used.

Response size cap (maxResponseBytes). A hard cap on response body size (default 100 MiB; 0 = unlimited) that defends against memory exhaustion from a hostile or buggy endpoint. CLI: --max-response-bytes. The engine enforces it, and the timeout, for a library user’s own transport too.

Read-only, no auth. The UBA Air Data API needs no API key; this client implements only the open, read-only GET endpoints.

Log record. Every diagnostic line the CLI writes to stderr: a timestamp, a level (ERROR, WARN, INFO) and a topic luftqualitaet.<area>, as text (log4j style) or with --log-format jsonl as one JSON object per line. The areas: cli (usage errors, commander’s messages, unexpected errors), api (the API’s answers and the notes on them: an error status, an unknown station, a malformed answer — bad JSON, the wrong shape or content type —, the notes on an empty window or an annual figure, the 409/500 hints), http (the connection, the cleartext warning, one WARN per retry before it waits) and output (a failed write to stdout). A record is always one line; control characters in it are escaped.


Library & internals. Terms for the TypeScript client and its internals — LuftqualitaetClient, the request engine, transport, retry/backoff, error types, query builder — now live in DEVELOPING.md.

View the source on GitHub →