How rare was this season?
Reinsurance and climate risk need a ranking, not a reading — where a season ranks in the historical record. One x402 call returns the empirical percentile, return period and the sample size it used.
“Was this July hot?” is the wrong question for a risk model. The right one is
“where does this July rank over the record, and over how many years?” — a
ranking, not a reading. An agent in reinsurance, climate risk or climate
finance needs the season’s value placed in the historical distribution at the
point, with the sample size exposed so it can judge the strength of the claim.
One paid call — GET /climate/return-period —
returns the seasonal value, its empirical percentile and rank, the corresponding
return period in years, and always the size of the sample it was ranked against.
The problem: a percentile is meaningless without its sample
A return period is a probability statement, and probability statements lie when the method and the sample are hidden. “Top 3% / a 1-in-35-year event” means one thing over 35 years of record and something much weaker over 12. Worse, a parametric fit (GEV and friends) can manufacture a confident-looking 1-in-100 figure from a short series — extrapolation dressed as measurement.
GET /climate/return-period does the honest version: it ranks the target year
empirically against the observed sample and tells you exactly how many years
that sample holds.
The call: a point, a season, a target year
Define the season either as a whole calendar month or as a custom
from_md/to_md window (no mix, no year-boundary wrap), pick the variable and
the seasonal statistic, and name the year to place:
GET /climate/return-period?lat=48.8566&lon=2.3522&month=7&year=2024&variable=temperature&stat=mean
GET /climate/return-period?lat=48.8566&lon=2.3522&from_md=06-01&to_md=08-31&year=2024&variable=precipitation&stat=sum
The statistic must be physically consistent with the variable: temperature
accepts mean (default) or max; precipitation accepts sum (default) or
max. The response places the year in the distribution:
| Field | What the agent learns |
|---|---|
value | the target year’s seasonal value (null if the year is uncovered) |
percentile | empirical percentile (rank / sample_years, %) |
rank | the value’s rank within the sample |
return_period_years | the empirical return period in years |
sample_years | how many historical years it was ranked against — always present |
method | always empirical |
Honesty: empirical, with the sample always on the table
This is the scope that makes the figure defensible — and the reason it is the most defensible derivative in the climate family:
- The method is empirical, full stop. The value is placed by its rank in
the observed sample;
methodis alwaysempirical. There is no GEV or other parametric fit and no confidence interval in this version — nothing is extrapolated beyond the record. sample_yearsis always returned. A percentile over 12 years and one over 60 are not the same claim, so the sample size is never hidden — the agent decides whether it is strong enough to act on.- A short sample is flagged, not faked. Below a floor of 20 sample years
the figures are still served, but
coverage.completeisfalsewith a reason such asinsufficient history: 14 years. - It is a grid value, not a station. ERA5 is a gridded reanalysis on a mesh
of about 0.25 degrees;
grid.distance_kmexposes how far the served cell sits from the requested point.
{
"data": {
"lat": 12.3456, "lon": 98.7654,
"season": "07-01..07-31", "year": 2024,
"variable": "precipitation", "stat": "sum", "unit": "millimetre",
"value": 612.8,
"percentile": 92.9, "rank": 13, "sample_years": 14,
"return_period_years": 14.0,
"method": "empirical",
"grid": { "lat": 12.25, "lon": 98.75, "distance_km": 11.07 },
"coverage": { "complete": false, "reason": "insufficient history: 14 years" }
},
"provenance": {
"source": "era5-copernicus",
"freshness": { "kind": "snapshot", "as_of": "2026-06-19T00:00:00Z" }
}
}
If the target year is not covered by the record, the ranking fields
(value, percentile, rank, return_period_years) come back null while
sample_years and method remain present — you still learn what the sample is.
Per the x402 golden rule, only requests the service genuinely cannot answer leave
the 200 range: invalid coordinates (INVALID_COORDS), an invalid year or season
(INVALID_PERIOD), an unknown or inconsistent variable/stat (INVALID_VARIABLE),
or a point with no historical sample 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.
The rarity question, after the balance and the departure
Return period is the rarity layer — the question you ask once you have the season’s value and know it was unusual:
GET /climate/aggregate— the seasonal value itself, the balance you then rank (see Season summaries for any GPS point).GET /climate/anomaly— how far that value sat from the 1991–2020 normal (see How far from normal was this month?).GET /climate/point— the raw daily values behind it all.
Aggregate tells you what the season was, anomaly tells you it was unusual, and return-period tells you how unusual, empirically.
Used for what it is — an empirical rank in the ERA5 record, with the method fixed,
the sample size always exposed and short histories flagged — GET /climate/return-period gives a risk agent a ranking it can defend, without an
account and without building a climatology from GRIB. For the full field
reference, season semantics and error codes, see the
GET /climate/return-period documentation.
ERA5 values are derived from Copernicus Climate Change Service (C3S) information.