Season summaries for any GPS point

A reporting agent needs the climate balance of a month or season — mean temperature, total rainfall, mean wind — not 90 daily lookups to roll up itself. One x402 call returns it from ERA5.

An agent writing a monthly or seasonal report needs the balance of a window at a point: how warm it was on average, how much rain fell in total, how the wind sat. Assembling that yourself means 30 to 90 individual daily lookups and a roll-up that has to use the right convention for each variable. One paid call — GET /climate/aggregate — returns the summary directly: mean temperature with its daily extremes, total precipitation and mean wind over a date range, computed from ERA5.

The problem: each variable aggregates differently

The trap in a season summary is that “average it” is wrong for half the variables. Precipitation has to be a total, not a mean — a month of rain is a sum, not an average daily figure. Wind direction cannot be averaged as plain degrees (the mean of 350° and 10° is not 180°). And “the min and max” is ambiguous: extremes of daily means are a different number from hourly Tmin/Tmax.

Get any of those conventions wrong and the report is quietly misleading. GET /climate/aggregate applies the convention that fits each family and tells you which one it used.

The call: a point and a window

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

GET /climate/aggregate?lat=48.8566&lon=2.3522&from=2024-06-01&to=2024-08-31
GET /climate/aggregate?lat=48.8566&lon=2.3522&from=2024-06-01&to=2024-08-31&variables=temperature

The window [from, to] is the unit of the product, capped at 366 days per call. The response is a UnifiedResponse carrying one aggregate per requested family:

FieldWhat the agent learns
temperaturemean_celsius, plus min_celsius / max_celsius of the daily means
precipitationtotal_mm — the sum over the window
windmean_speed_ms and mean_direction_deg
days_countedhow many covered days contributed
gridthe cell that answered, and its distance_km from the point
coveragewhether every day had a usable value for each family

Honesty: the conventions are explicit

This is the scope that keeps a summary trustworthy:

  • Precipitation is a total, not a mean. total_mm adds the daily totals over the covered days.
  • Temperature and wind are means over the covered days. Wind direction is averaged as a vector, not as a naive scalar mean of degrees, so the near-north wrap-around does not corrupt it.
  • min_celsius / max_celsius are extremes of the daily means — the coldest and warmest days in the window, not the lowest and highest instantaneous readings. For true daily Tmin/Tmax extremes, use GET /climate/indices.
  • 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, so the agent can judge how representative it is.

Partial coverage is still an answer

When some days in the window have no grid value, they are dropped: days_counted reflects the covered days, a sum like total_mm is the total over those days only, and a requested family with no data comes back null — all at 200, with coverage.complete: false explaining the gap.

{
  "data": {
    "lat": 48.8566, "lon": 2.3522,
    "from": "2024-06-01", "to": "2024-06-30",
    "days_counted": 28,
    "temperature": { "mean_celsius": 19.7, "min_celsius": 12.1, "max_celsius": 27.0 },
    "precipitation": { "total_mm": 41.2 },
    "wind": null,
    "grid": { "lat": 48.75, "lon": 2.25, "distance_km": 13.42 },
    "coverage": { "complete": false, "reason": "no wind data at this grid cell; 2 days in the window have no value" }
  },
  "provenance": {
    "source": "era5-copernicus",
    "freshness": { "kind": "snapshot", "as_of": "2026-06-19T00:00:00Z" }
  }
}

This is the x402 golden rule: the agent pays for the answer to its question, and a partial-but-honest summary is a valid answer — read days_counted and coverage before trusting it. 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 with no covered day at all (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.

One window, many questions

GET /climate/aggregate is the summary layer over the daily series. It pairs with the rest of the climate family depending on the question:

Reach for the aggregate when the deliverable is the season’s balance itself — analytics, reporting, energy operations.

Used for what it is — a reproducible period summary from ERA5, with each variable aggregated by its correct convention and the served cell and coverage exposed honestly — GET /climate/aggregate gives a reporting agent the month or season in one call, without an account and without rolling up GRIB. For the full field reference, aggregation conventions and error codes, see the GET /climate/aggregate documentation.

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