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:

FieldWhat the agent learns
valuethe target year’s seasonal value (null if the year is uncovered)
percentileempirical percentile (rank / sample_years, %)
rankthe value’s rank within the sample
return_period_yearsthe empirical return period in years
sample_yearshow many historical years it was ranked against — always present
methodalways 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; method is always empirical. There is no GEV or other parametric fit and no confidence interval in this version — nothing is extrapolated beyond the record.
  • sample_years is 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.complete is false with a reason such as insufficient 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_km exposes 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:

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.