Community. Driven. Weather. Data. | Always Ad-Free | Developer FriendlyChecking statusDiscord
WxAlerts.org, Community Driven Weather Data
Support us
Sign in
API

Weather API

Measured conditions from the nearest station plus a seven-day forecast, in one small response built for a screen.


Base URL: https://api.wxalerts.org

One endpoint. Give it a point, and it returns what is happening there now and what is expected, sized for something that renders it.

GET /weather?lat=33.215&lon=-97.133
GET /weather?q=denton+tx
GET /weather?location_id=12345

No authentication. CORS is open.

{
  "server_time": "2026-08-31T17:29:02Z",
  "location": {
    "name": "Denton", "display_name": "Denton, TX", "state": "TX",
    "lat": 33.2174, "lon": -97.1413, "timezone": "America/Chicago"
  },
  "units": { "system": "us", "fields": { "temperature": { "unit": "F", "label": "°F" } } },
  "current": {
    "observed_at": "2026-08-31T17:29:00Z",
    "temperature": 96.0, "dewpoint": 68.5, "relative_humidity": 41.0,
    "wind_speed": 4.0, "wind_gust": 6.0,
    "wind_direction": 152.0, "wind_direction_cardinal": "SSE",
    "pressure": 30.06, "visibility": 10.0,
    "precip_1h": 0.0, "precip_24h": 0.0, "snow_depth": null,
    "conditions": null,
    "station": {
      "station_id": "metar:KDTO", "name": "Denton Enterprise Arpt, TX",
      "source": "metar", "distance_m": 8100, "age_seconds": 240
    }
  },
  "hourly": [
    {
      "time": "2026-08-31T13:00:00-05:00",
      "sky": "Partly cloudy", "precip_type": null,
      "temperature": 93.4, "dewpoint": 70.1, "relative_humidity": 47.0,
      "wind_speed": 9.2, "wind_gust": 15.1,
      "wind_direction_cardinal": "S",
      "cloud_cover": 41.0, "precip_probability": 4.0, "precip_amount": 0.0
    }
  ],
  "daily": [
    {
      "date": "2026-08-31", "hours": 17,
      "sky": "Clear", "precip_type": null,
      "high": 99.9, "low": 80.0, "dewpoint_high": 72.4,
      "wind_speed": 10.3, "wind_gust": 16.1, "wind_direction_cardinal": "S",
      "cloud_cover": 6.0, "precip_probability": 0.0, "precip_amount": 0.0
    }
  ]
}

Now is measured. The rest is forecast.

current comes from the surface weather stations around the point: airfield observations, mesonets and CWOP stations. It is not the model’s opinion of the present. A model’s analysis hour is still a forecast however recently it ran, and there is usually a thermometer within a few miles that is not guessing.

hourly and daily are the National Blend of Models. The two are never blended together and they can disagree, which is not a bug: an observation is a fact about this minute and a forecast is a guess about the next one.

Both start where the reader is standing in time: hourly[0] is the hour containing server_time and daily[0] is today at the forecast location. A cycle’s series really begins in the past (NBM runs four times a day and its first step is an hour after the cycle behind it) and that reach-back is cut off here so that a strip can be drawn straight from the array. GET /forecast serves the same series whole, past hours included, for clients charting a run rather than displaying it.

station names the instrument the reading is attributed to: the one that supplied most of the fields. Where it has no sensor for something, the next station nearby fills that field silently.

current is null when no station within 50 miles has reported in the last two hours. That is a different statement from every field coming back empty, and it is deliberate: a reading from an airfield 200 miles away is a true reading and a false claim about here.

conditions is the station’s own words for what is falling: "-RA BR", "haze". It is null when the station reports none, which is not the same as fair weather. For a phrase covering the sky as well, read hourly[0].sky.

One word for the sky

Every hour and every day carries sky: a single phrase, decided on the server.

Clear · Mostly sunny · Partly cloudy · Mostly cloudy · Overcast from cloud cover, when little or nothing is expected to fall
Scattered rain · Scattered showers chance of precipitation ≥ 25%
Rain likely · Snow likely · Precipitation likely ≥ 55%
Storms likely ≥ 55%, with a thunder probability ≥ 30%

precip_type is one of rain, snow, sleet or freezing rain, or null when none is forecast.

The store publishes numbers, not prose, so this wording is derived. It is derived here rather than in each client on purpose: the underlying inputs are four independent precipitation-type probabilities that do not sum to 100, a cloud fraction and a thunder probability, and two panels in one house deriving their own answers is how they end up disagreeing about the same hour.

Fields

A null almost always means nothing publishes that field at that location, not that something failed.

current

Measured. Every one of these keys is always present; the value is null where no station nearby reports it.

field notes
temperature, dewpoint, relative_humidity A METAR carries no humidity and a CWOP packet carries no dew point; the missing half of that pair is derived from the other
wind_speed, wind_gust, wind_direction Direction is degrees true, blowing from. wind_direction_cardinal gives the compass point
pressure Sea-level, or the altimeter setting where there is no sea-level reduction. Stations report up to three pressures; this is one of them, chosen
visibility
precip_1h, precip_24h, snow_depth

hourly

From the hour containing server_time; see above.

field notes
time Local to the forecast location, with its offset. There is no separate offset field
sky, precip_type See above
temperature, dewpoint, relative_humidity
wind_speed, wind_gust, wind_direction_cardinal
cloud_cover
precip_probability P(> 0.254 mm), the chance of rain
precip_amount Liquid-equivalent, over the hour ending here

daily

Local calendar days at the forecast location, not UTC days, from today onward. A UTC boundary falls in the evening across the Americas, which files an evening thunderstorm under tomorrow and puts tonight’s low on the wrong card.

field notes
date
high, low The day’s temperature range
dewpoint_high
wind_speed, wind_gust The day’s maxima
wind_direction_cardinal Prevailing, averaged as a unit vector, because the arithmetic mean of 350° and 10° is 180°, the opposite direction
cloud_cover The day’s mean
precip_probability The day’s maximum
precip_amount The day’s total
hours Forecast hours behind this day

How much to ask for

GET /weather?lat=33.2&lon=-97.1&hours=12&days=5
default range
hours 24 1–168
days 7 1–8

A panel showing the next twelve hours should ask for twelve. The forecast runs seven days ahead whatever you ask for; these only decide how much of it crosses the wire.

Units

GET /weather?lat=33.2&lon=-97.1&units=us
value meaning
si Exactly what the model published: Kelvin, m/s, Pascals, metres
metric °C, km/h, mm, hPa
us °F, mph, in, inHg
uk °C and mm, but mph and miles
auto Chosen from the caller’s country, via Cloudflare

Every response carries a units block naming the unit of every field it returned, so a client never has to infer whether pressure came back in hPa or inHg. A gauge with a mislabelled scale looks entirely correct.

Observed and forecast fields share one vocabulary and one map. A temperature in current and a temperature in hourly are the same kind of number in the same unit, so both render through the same code, including high and low, which are declared as temperatures rather than leaving you to work it out.

Coverage

The forecast covers the United States and its territories (the Lower 48, Alaska, Hawaii, Puerto Rico and Guam) and nowhere else. A point outside it returns 200 with hourly and daily empty, not 404. There is no error to handle; there is simply no model there.

current is not bounded that way. CWOP is a worldwide network, so a point with no forecast can still have a thermometer next to it.

Polling

See limits. The response is cached for 60 seconds, which is the station’s cadence rather than the model’s: CWOP stations report every five minutes and METARs hourly, while NBM runs four times a day. Polling faster than a minute gains nothing; polling once a minute is the most a display can usefully do.