# Heating, cooling and growing degree-days for any location > Energy and agriculture agents need HDD, CDD and GDD over a period, not raw temperatures to sum themselves. One paid call computes them from ERA5 with a declared method, no account. Published 2026-06-28 · Updated 2026-08-16 · HTML version: https://invoket.com/blog/heating-and-cooling-degree-days-for-any-location --- An agent forecasting energy demand or staging a crop does not want a year of daily temperatures — it wants the *aggregate*: how much heating, cooling or growth the season actually added up to. That number is **degree-days**, and assembling it correctly means pulling a daily series, choosing a base, applying a documented method and excluding gaps. One paid call — [`GET /climate/degree-days`](/docs/api/climate-degree-days) — returns heating (HDD), cooling (CDD) and growing (GDD) degree-days for a GPS point over any window, computed from ERA5, with the method stated in the response. ## The problem: degree-days are a method, not just a sum Degree-days look trivial and aren't, because the answer depends entirely on *which method and which base* you used — and an agent that invents either gets a number that looks right and is wrong. You need a consistent daily mean series, a declared base temperature, and a rule for the days that have no data. Done by hand, that is hours of scripting over raw climate files; done inconsistently, two runs disagree. `GET /climate/degree-days` does it one way, every time, and tells you which way. ## The call: a point, a window, a base Give a latitude, a longitude, an inclusive date range, and optionally the families and base you want: ```http GET /climate/degree-days?lat=48.8566&lon=2.3522&from=2024-01-01&to=2024-12-31&kind=hdd GET /climate/degree-days?lat=48.8566&lon=2.3522&from=2024-04-01&to=2024-09-30&kind=gdd&base=10 ``` The window `[from, to]` is the unit of the product, capped at **366 days** per call. The response is a `UnifiedResponse` carrying the totals plus the parameters that produced them: | Field | What the agent learns | |----------------|----------------------------------------------------------------| | `hdd` / `cdd` / `gdd` | the requested degree-day totals over the window | | `base` | the base temperature in Celsius actually applied | | `days_counted` | how many covered days contributed to the sums | | `method` | always `mean_temperature` — the computation rule | | `coverage` | whether every day in the window had a usable value | Defaults are explicit and echoed back: the base is **18 °C** when HDD or CDD is requested (the standard energy base) and **10 °C** for a GDD-only request (a common growth base). Supply `base` to override it. ## Honesty: the method is declared, and GDD is not capped This is the scope point that keeps the totals trustworthy. Degree-days here use the **mean-temperature method** — the standard NWS / EIA / WMO convention — and the response says so via `method: "mean_temperature"`. For each day: - `HDD = max(0, base − Tmean)` - `CDD = max(0, Tmean − base)` - `GDD = max(0, Tmean − base)` summed over the covered days. Two honesty notes the endpoint makes explicit: - **GDD is plain and uncapped.** This is mean-temperature GDD with no Tmin/Tmax clamping and no upper cutoff. Some agronomic models cap daily contributions; this endpoint deliberately does not, so you know exactly what you are getting. - **It is a grid value, not a station.** ERA5 is a gridded reanalysis on a mesh of about 0.25 degrees. Daily means are aggregate store values, not a weather-station reading. ## Gaps are excluded, not invented When some days inside the window have a grid gap, they are **dropped from the sum** rather than interpolated. The call is still a **200**: `days_counted` reflects the days that actually contributed and `coverage.complete: false` explains the shortfall. ```json { "data": { "lat": 48.8566, "lon": 2.3522, "from": "2024-06-01", "to": "2024-06-30", "base": 18, "days_counted": 28, "hdd": 12.4, "cdd": 41.9, "gdd": 233.6, "method": "mean_temperature", "coverage": { "complete": false, "reason": "2 days in the window have no grid value and were excluded" } }, "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 "here is the total over the days that exist" 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 out-of-bounds base (`INVALID_BASE`), 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-degree-days) for the current figure. ## A derived signal, not raw data Degree-days are a *derivative* of the daily climate series. When an agent needs the underlying variables for a single date — temperature, precipitation, wind — that is [`GET /climate/point`](/docs/api/climate-point) (see [Historical weather for any GPS point and date, from ERA5](/blog/historical-weather-for-any-gps-point)). When it needs period summaries rather than degree-day totals, [`GET /climate/aggregate`](/docs/api/climate-aggregate) rolls a window into monthly and seasonal figures. Reach for degree-days specifically when the decision is demand-and-growth shaped: heating/cooling load, weather hedging, crop phenology. Used for what it is — a reproducible, method-declared degree-day total from ERA5, with the base, the day count and the coverage exposed honestly — `GET /climate/degree-days` gives an energy or agriculture agent the aggregate it actually reasons over, without an account and without scripting over GRIB. For the full field reference, base defaults and error codes, see the [`GET /climate/degree-days` documentation](/docs/api/climate-degree-days). ERA5 values are derived from Copernicus Climate Change Service (C3S) information.