# Monthly and seasonal climate 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 paid call returns it from ERA5. Published 2026-06-28 · Updated 2026-08-16 · HTML version: https://invoket.com/blog/season-summaries-for-any-gps-point --- 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`](/docs/api/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: ```http 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: | Field | What the agent learns | |-----------------|----------------------------------------------------------------| | `temperature` | `mean_celsius`, plus `min_celsius` / `max_celsius` of the daily means | | `precipitation` | `total_mm` — the **sum** over the window | | `wind` | `mean_speed_ms` and `mean_direction_deg` | | `days_counted` | how many covered days contributed | | `grid` | the cell that answered, and its `distance_km` from the point | | `coverage` | whether 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`](/docs/api/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. ```json { "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](/docs/quickstart) walks the discover → `402` → pay → replay cycle with runnable snippets, and [For agents](/docs/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](https://api.invoket.com/catalog); see the [endpoint reference](/docs/api/climate-aggregate) 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: - [`GET /climate/point`](/docs/api/climate-point) — the underlying daily values for a single date (see [Historical weather for any GPS point and date, from ERA5](/blog/historical-weather-for-any-gps-point)). - [`GET /climate/anomaly`](/docs/api/climate-anomaly) — how far this window sat from the long-term normal. - [`GET /climate/return-period`](/docs/api/climate-return-period) — how rare a season's value was, empirically. 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](/docs/api/climate-aggregate). ERA5 values are derived from Copernicus Climate Change Service (C3S) information.