Base URL: https://api.wxalerts.org
A model sounding for any point: temperature, dewpoint, height and wind on all 39 HRRR pressure levels, and the surface beneath them, for every forecast hour of the newest run. Raw numbers, for computing CAPE, shear and helicity yourself or drawing your own Skew-T and hodograph.
GET /forecast/sounding?lat=35.2&lon=-97.4
GET /forecast/sounding?q=norman+ok&hours=6
GET /forecast/sounding?lat=35.2&lon=-97.4&valid_from=2026-11-09T00:00Z&valid_to=2026-11-09T06:00Z&wind=uv
No authentication. CORS is open. This endpoint has its own limit, 30
requests a minute per client, tighter than the
rest of the API because one call can carry 49 hours of a full
column. Past it you get 429 with a Retry-After. A run’s hours only ever
arrive, never change, so cache what you have and ask only for the hours you
are missing (valid_from).
| parameter | |
|---|---|
lat, lon |
the point. Or q (a place name) or location_id, as on /forecast |
hours |
at most this many hours, from f00. Default: every hour on hand |
valid_from, valid_to |
ISO 8601 limits on valid time |
wind |
both (default), uv, or speeddir |
What a response holds
{
"grid_point": { "i": 902, "j": 407, "lat": 35.2076, "lon": -97.40682, "resolution_km": 3.0 },
"run": { "model": "hrrr", "cycle": "2026-11-08T22:00:00Z",
"hours_available": 11, "hours_expected": 19, "complete": false },
"levels_hpa": [1000.0, 975.0, 950.0, "...", 100.0, 75.0, 50.0],
"hours": [
{
"valid_time": "2026-11-08T22:00:00Z",
"forecast_hour": 0,
"surface": {
"temperature_2m_k": 293.6, "dewpoint_2m_k": 277.1, "pressure_hpa": 977.7,
"u10_ms": 1.3, "v10_ms": -0.9, "wind_speed_10m_ms": 1.6, "wind_direction_10m_deg": 305.0,
"u80_ms": 1.4, "v80_ms": -1.6, "wind_speed_80m_ms": 2.1, "wind_direction_80m_deg": 319.0,
"pbl_height_m": 1082.0
},
"levels": [
{ "pressure_hpa": 1000.0, "below_ground": true, "height_m": null, "temperature_k": null,
"dewpoint_k": null, "u_ms": null, "v_ms": null, "wind_speed_ms": null, "wind_direction_deg": null },
{ "pressure_hpa": 800.0, "below_ground": false, "height_m": 2050.0, "temperature_k": 281.7,
"dewpoint_k": 255.3, "u_ms": 0.8, "v_ms": -2.7, "wind_speed_ms": 2.8, "wind_direction_deg": 343.0 }
]
}
]
}
- Levels, bottom up: 1000 to 125 hPa every 25, then 100, 75 and 50. That is the native HRRR column, so the lowest kilometre has its full detail.
- Units are SI: K, m, m/s. Pressure is hPa. Heights are geopotential
metres above sea level; the surface block’s
pbl_height_mis above ground. - Below ground. Every hour has all 39 levels, so position k is always the
same pressure. A level whose pressure exceeds that hour’s surface pressure is
marked
below_ground: truewith every valuenull: the model extrapolates under terrain and those numbers describe no air. - Winds are degrees from true north, the direction FROM. HRRR publishes them relative to its own grid; they are turned before they are stored.
- Precision: 0.1 K and 0.1 m/s, heights to 1 m.
Which run, and how much of it
The newest HRRR run with at least its first two hours on hand. Every run goes
to 18 hours; the 00, 06, 12 and 18 UTC runs go to 48. A run fills in over
roughly half an hour after it is published, so a response can be partial:
hours_available against hours_expected, and complete once every hour is
in. Ask again later for the rest.
The grid is the HRRR’s own 3 km CONUS grid, not averaged. grid_point is the
cell your point fell in. A point outside the grid is a 404; no run on hand
is a 503.

