How far from normal was this month?

ESG reports and parametric triggers need a departure from a stable baseline, not a raw reading. One x402 call returns the ERA5 value, the 1991-2020 WMO normal, and the anomaly between them.

“This July was 2.7 °C above normal here” is a sentence an ESG report or a parametric trigger lives on — and it is only meaningful if normal is a stable, named baseline rather than a convenient short window. An agent producing that statement needs the observed value, the climatological normal, and the difference between them, computed against a reference it can cite. One paid call — GET /climate/anomaly — returns exactly that: the departure of the observed ERA5 value from the 1991-2020 WMO climate normal, for temperature, precipitation and wind.

The problem: an anomaly is only as good as its baseline

The failure mode here is subtle. You can compute “above average” against anything — last year, the last five years, a fitted trend — and get a number that looks authoritative and means nothing comparable. A defensible anomaly is measured against a standard baseline: the WMO 30-year climate normal, currently the 1991-2020 period (WMO-No. 1203). Mix baselines across a report and the numbers stop being comparable.

GET /climate/anomaly uses the 1991-2020 normal as its only reference and stamps it into every response, so the baseline is never ambiguous.

The call: a point and a window

Give a latitude, a longitude, an inclusive date range, and optionally the families you want:

GET /climate/anomaly?lat=48.8566&lon=2.3522&from=2024-07-01&to=2024-07-31
GET /climate/anomaly?lat=48.8566&lon=2.3522&from=2024-07-01&to=2024-07-31&variables=temperature

The window [from, to] is the unit of the product, capped at 366 days per call. For each requested family the response gives the three numbers an anomaly needs — observed, normal, and their difference:

FamilyObservedNormal (1991-2020)Anomaly
temperatureobserved_celsiusnormal_celsiusanomaly_celsius
precipitationobserved_mmnormal_mmanomaly_mm
windobserved_speed_msnormal_speed_msanomaly_speed_ms

The anomaly is always observed minus normal, and the baseline used is echoed in reference_period (e.g. 1991-2020).

Honesty: it is observed minus a 30-year monthly normal

This is the scope that makes the figure citable:

  • The baseline is fixed and stated. The reference is the 1991-2020 WMO normal — a 30-year baseline — surfaced in reference_period. The endpoint never dresses up a short window as a “normal.”
  • The normal is monthly. Each observed day is paired with the normal for its month, so over a multi-month window the normals are weighted by how many days fall in each month. Temperature and wind are means; precipitation is the observed total versus the sum of the daily normals.
  • It is a grid value, not a station. ERA5 is a gridded reanalysis on a mesh of about 0.25 degrees; grid.distance_km exposes how far the served cell sits from the requested point.

An unpaired family is null, with the reason

An anomaly needs both an observation and a normal. A day counts only when it has both; a family that cannot be paired comes back null, and coverage distinguishes the two causes — an observation gap versus a climatological normal not available. The request still succeeds at 200 as long as another family was paired.

{
  "data": {
    "lat": 48.8566, "lon": 2.3522,
    "from": "2024-07-01", "to": "2024-07-31",
    "reference_period": "1991-2020",
    "days_counted": 31,
    "temperature": { "observed_celsius": 22.8, "normal_celsius": 20.1, "anomaly_celsius": 2.7 },
    "wind": null,
    "grid": { "lat": 48.75, "lon": 2.25, "distance_km": 13.42 },
    "coverage": { "complete": false, "reason": "wind: climatological normal not available" }
  },
  "provenance": {
    "source": "era5-copernicus",
    "freshness": { "kind": "snapshot", "as_of": "2026-06-19T00:00:00Z" }
  }
}

That distinction matters for a reporting agent: “no observation” and “no normal” are different gaps, and the response tells you which one you hit. Per the x402 golden rule, only requests the service genuinely cannot answer leave the 200 range: invalid coordinates (INVALID_COORDS), a bad or over-long period (INVALID_PERIOD), an unknown family (INVALID_VARIABLE), or a window where nothing can be paired (OUT_OF_RANGE).

Where it fits in the x402 loop

Each paid call follows the same pattern as every Invoket endpoint. The Quickstart walks the discover → 402 → pay → replay cycle with runnable snippets, and For agents covers the discovery surfaces and the live /catalog. Price and accepted rails are not pinned in this article — they are served live by the catalog; see the endpoint reference for the current figure.

Raw value, balance, departure, rarity

Anomaly is the departure layer of the climate family — pick the endpoint that matches the question:

Reach for anomaly when the deliverable is “above/below normal by how much” — parametric insurance and ESG / climate reporting.

Used for what it is — an observed-minus-normal departure against the fixed 1991-2020 WMO baseline, with the reference period stamped in and the served cell and coverage exposed honestly — GET /climate/anomaly gives an agent a citable deviation, without an account and without building a climatology from GRIB. For the full field reference, baseline semantics and error codes, see the GET /climate/anomaly documentation.

ERA5 values are derived from Copernicus Climate Change Service (C3S) information.