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