weather-unified POC

Unified weather API across NOAA, ECMWF and more. POC running on Contabo VPS.

What it does

Single REST API that returns forecast values from multiple models at a point, over a bounding box, or as a vertical profile. Variables are exposed in CF-standard names so the same call works across models. Implements OGC API-EDR for multi-variable, multi-location queries.

ModelCoverageResolutionHorizonArchive
GFSglobal0.25°384h1 year
ECMWF IFSglobal0.25°360h3.5 years
HRRRCONUS~3km18h1 year
NAMN. America12km84h1 year
ICON-EUEurope6.5km120hrolling
AROMEFrance2.5km42hrolling

Try it

// Output appears here

Endpoints

GET  /healthz
GET  /models                                       list models + variables
GET  /models/{model}/variables
GET  /point  ?model=&var=&vars=&lat=&lon=&lead_from=0&lead_to=24
GET  /bbox   ?model=&var=&west=&south=&east=&north=&lead_hours=0&fmt=json|netcdf
GET  /profile ?model=&lat=&lon=&lead_hours=0
GET  /stac/search ?model=&from=&to=&bbox=&limit=
GET  /refs/{model}                                 kerchunk refs JSON for xarray

# OGC API-EDR (multi-variable, multi-location)
GET  /edr/conformance
GET  /edr/collections
GET  /edr/collections/{model}
GET  /edr/collections/{model}/position             single point, CoverageJSON
     ?coords=POINT(lon+lat)¶meter-name=var1,var2&datetime=+0h/+48h
GET  /edr/collections/{model}/locations            multi-point, GeoJSON
     ?lats=...&lons=...¶meter-name=var1,var2&lead_from=0&lead_to=24

GET  /docs                                         OpenAPI spec UI

Training & inference (ML)

Download a kerchunk refs JSON via /refs/{model}, then read directly with xarray. Data flows from the source S3 bucket straight to your compute (no transit through this API).

import fsspec, xarray as xr

# small (~MB), describes how to read the GRIB2 files
refs_url = "https://5-189-137-60.sslip.io/refs/gfs"

fs = fsspec.filesystem(
    "reference",
    fo=refs_url,
    remote_protocol="s3",
    remote_options={"anon": True},   # NOAA Open Data, free egress
)
ds = xr.open_dataset(fs.get_mapper(""), engine="zarr", consolidated=False)

# everything cfgrib exposed is now a regular xarray Dataset.
t2m = ds["t2m"]                       # (step, lat, lon)
print(t2m.sel(latitude=48.85, longitude=2.35, method="nearest").values)

For ECMWF: /refs/ecmwf-ifs. Add ?init_time=2026-06-19T00 to pin a specific run.

Variables (CF names)

Surface: air_temperature_2m, dewpoint_temperature_2m, wind_u_10m, wind_v_10m, wind_gust_10m, mean_sea_level_pressure, total_precipitation, total_cloud_cover, low_cloud_cover, mid_cloud_cover, high_cloud_cover, cape, visibility, snow_depth, relative_humidity_2m.

Pressure levels (1000 / 850 / 700 / 500 / 300 / 250 hPa): temperature, u_wind, v_wind, specific_humidity, geopotential_height, vertical_velocity.

Status

Roadmap: AROME (Météo-France), WW3 (wave model), 1-year HRRR/NAM backfill completion.

Loading catalog status…

Source: github.com/pdrion/weather_ruse