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 x402 call computes them from ERA5 with a declared method, no account.

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 — 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:

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:

FieldWhat the agent learns
hdd / cdd / gddthe requested degree-day totals over the window
basethe base temperature in Celsius actually applied
days_countedhow many covered days contributed to the sums
methodalways mean_temperature — the computation rule
coveragewhether 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.

{
  "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 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.

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 (see Historical weather for any GPS point and date). When it needs period summaries rather than degree-day totals, GET /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.

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