Weather & Hazards API
The Weather Intelligence API returns weather and environmental data as clean JSON.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
The primary environment_current endpoint returns a location's temperature, feels-like, wind, condition symbol and air quality, and you can pull a forecast, air_quality, alerts, nearby hazards, disasters and earthquakes. It is built for weather apps, logistics and risk tools that need weather and hazard data from one endpoint. One ReefAPI key, one shared credit pool, the standard envelope.
What each action reads, and in which units and timezone
weather-intel is thirteen actions over nine different public datasets, and they do not share a unit system or a timestamp convention. The forecast actions speak UTC, the archive speaks local wall-clock, and the US path passes some NWS strings through untouched. Every response also carries a source block with source_updated_at, fetched_at, staleness_minutes, stale and confidence, so you can tell how old the underlying model run was.
| Action | Underlying record | Units and timestamps |
|---|---|---|
| forecast (default) | MET Norway Locationforecast 2.0, hourly for ~2.5 days then 6-hourly to ~day 9 | metric = C, m/s, mm; every time is UTC with a trailing Z |
| forecast source=us_nws | NWS gridpoint forecast; grid_id, grid_x, grid_y under us_official | temperature converted to C, but wind_speed stays a string like "10 mph" and times carry a local offset such as -04:00 |
| historical | Open-Meteo ERA5 archive, 1940-01-01 onward | read daily_units: wind is km/h and snowfall cm even in metric, and time is a local date with no zone |
| air_quality | OpenAQ nearest-station measurements | ug/m3; aqi_us on US EPA PM2.5 2024 breakpoints, aqi_eu on the 1-6 EAQI band, each with its own scale string |
| air_quality_forecast | Open-Meteo CAMS forecast plus pollen | ug/m3 and grains/m3; pollen is the European domain only and null elsewhere |
| alerts, EU country | EUMETNET MeteoAlarm, EMMA region level | fields identifier, geocode_emma_id and title; timestamps +00:00 |
| alerts, US state code | NWS api.weather.gov | fields id (urn:oid:...), headline, instruction, response and ends; timestamps in the state's local offset |
| marine | Open-Meteo ocean-wave grid | meters, seconds, degrees; on land every wave value is null with an on_land_note |
| earthquakes | USGS fdsnws catalog | magnitude with magnitude_type (mww, mb), depth_km, distance_km, PAGER alert |
| hazards_nearby and disasters | GDACS | alert_level green/orange/red plus alert_score, distance_km, report_url |
| geocode | Open-Meteo geocoding over GeoNames | GeoNames id, IANA timezone, elevation_m, feature_code (PPLA, PPL, AIRP) |
In alerts, country="CA" means California, not Canada. Any two-letter US state or marine code routes to NWS, and a MeteoAlarm member slug or ISO2 routes to the European feed. Canada is covered by neither, and an unrecognized value returns INVALID_PARAM naming both vocabularies.
Real request and response JSON
Captured from the indexed primary action, environment_current, on .
{
"method": "POST",
"url": "https://api.reefapi.com/weather-intel/v1/environment_current",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"lat": 52.52,
"lon": 13.405
}
}{
"ok": true,
"meta": {
"api": "weather-intel",
"endpoint": "environment_current",
"mode": "live",
"latency_ms": 6379.5,
"record_count": 1,
"bytes": 0,
"cache_hit": false,
"blocks": [
"air_quality",
"alerts",
"hazards"
]
},
"data": {
"location": {
"lat": 52.52,
"lon": 13.405
},
"units": "metric",
"weather": {
"time": "[redacted-phone]T17:00:00Z",
"temperature": 23.7,
"feels_like": 23.7,
"humidity_pct": 44.6,
"wind_speed": 4.8,
"wind_gust": null,
"wind_direction_deg": 294.5,
"pressure_hpa": 1010.3,
"cloud_cover_pct": 14.8,
"fog_pct": 0,
"dew_point": 10.9,
"uv_index_clear_sky": 0.5,
"precipitation": 0,
"precipitation_window_hours": 1,
"symbol": {
"code": "fair_day",
"condition": "mostly_clear",
"intensity": "normal",
"is_showers": false,
"has_thunder": false,
"day_night": "day"
}
},
"air_quality": {
"pollutants": {
"no2": {
"value": 8.78,
"unit": "µg/m³",
"measured_at": "[redacted-phone]T16:00:00Z",
"age_hours": 1.3,
"station": "Berlin Mitte",
"station_id": 3019,
"station_distance_km": 1.18,
"provider": "EEA"
},
"pm10": {
"value": 27.57,
"unit": "µg/m³",
"measured_at": "[redacted-phone]T16:00:00Z",
"age_hours": 1.3,
"station": "Berlin Mitte",
"station_id": 3019,
"station_distance_km": 1.18,
"provider": "EEA"
},
"pm25": {
"value": 16.49,
"unit": "µg/m³",
"measured_at": "[redacted-phone]T16:00:00Z",
"age_hours": 1.3,
"station": "Berlin Mitte",
"station_id": 3019,
"station_distance_km": 1.18,
"provider": "EEA"
},
"co": {
"value": 250,
"unit": "µg/m³",
"measured_at": "[redacted-phone]T16:00:00Z",
"age_hours": 1.3,
"station": "Berlin Neukölln",
"station_id": 2993,
"station_distance_km": 3.82,
"provider": "EEA"
},
"o3": {
"value": 100.72,
"unit": "µg/m³",
"measured_at": "[redacted-phone]T16:00:00Z",
"age_hours": 1.3,
"station": "Berlin Neukölln",
"station_id": 2993,
"station_distance_km": 3.82,
"provider": "EEA"
}
},
"aqi_us": {
"value": 65,
"category": "moderate",
"dominant_pollutant": "pm25",
"per_pollutant": {
"pm25": 65,
"pm10": 26
},
"scale": "US EPA AQI (PM2.5 2024 breakpoints); computed from listed pollutants only"
},
"aqi_eu": {
"index": 3,
"category": "moderate",
"dominant_pollutant": "o3",
"per_pollutant": {
"pm25": "fair",
"pm10": "fair",
"no2": "good",
"o3": "moderate"
},
"scale": "European Air Quality Index (EAQI) bands"
},
"nearest_station_km": 1.18,
"stale_readings_skipped": 21,
"insufficient_data": false
},
"alerts": {
"active": [
{
"identifier": "[redacted-phone].DWD.PVW.[redacted-phone]dbed1-2c0c-42c2-be[redacted-phone].MUL",
"event": "heavy thunderstorms with gale- or storm-force gusts, heavy rain and hail",
"color": null,
"hazard": null,
"severity": "moderate",
"urgency": "immediate",
"certainty": "likely",
"status": "actual",
"message_type": "update",
"area": "Bodenseekreis",
"geocode_emma_id": "DE271",
"onset": "[redacted-phone]T16:31:00+00:00",
"effective": null,
"expires": "[redacted-phone]T17:30:00+00:00",
"sent": "[redacted-phone]T16:31:00+00:00",
"title": "Orange Thunderstorm Warning issued for Germany - Bodenseekreis"
},
{
"identifier": "[redacted-phone].DWD.PVW.[redacted-phone]d64efea-72bb-4822-833c-8c7d688c51bb.MUL",
"event": "heavy rain",
"color": null,
"hazard": null,
"severity": "moderate",
"urgency": "immediate",
"certainty": "likely",
"status": "actual",
"message_type": "alert",
"area": "Kreis Cuxhaven - Küste",
"geocode_emma_id": "DE045",
"onset": "[redacted-phone]T02:00:00+00:00",
"effective": null,
"expires": "[redacted-phone]T13:00:00+00:00",
"sent": "[redacted-phone]T13:56:00+00:00",
"title": "Orange Rain Warning issued for Germany - Kreis Cuxhaven - Küste"
},
{
"identifier": "[redacted-phone].DWD.PVW.[redacted-phone].e5bdb[redacted-phone]bad-96bc-7190d0afe854.MUL",
"event": "wind gusts",
"color": null,
"hazard": null,
"severity": "minor",
"urgency": "immediate",
"certainty": "likely",
"status": "actual",
"message_type": "update",
"area": "Stadt Emden",
"geocode_emma_id": "DE154",
"onset": "[redacted-phone]T06:00:00+00:00",
"effective": null,
"expires": "[redacted-phone]T19:00:00+00:00",
"sent": "[redacted-phone]T17:21:00+00:00",
"title": "Yellow Wind Warning issued for Germany - Stadt Emden"
}
],
"country": {
"slug": "germany",
"name": "Germany"
},
"matched_via": "point-in-polygon",
"coverage": "meteoalarm",
"coverage_note": "country-level MeteoAlarm warnings (EMMA regions) — not point-precise"
},
"hazards": {
"events": [
{
"event_id": 1104019,
"episode_id": 2,
"type": "flood",
"type_code": "FL",
"name": "[redacted-name]",
"alert_level": "green",
"alert_score": 1,
"severity": 0,
"severity_text": "Magnitude 0 ",
"country": "Germany",
"iso3": "DEU",
"from": "[redacted-phone]T01:00:00",
"to": "[redacted-phone]T01:00:00",
"is_current": true,
"coordinates": {
"lat": "[trimmed-depth]",
"lon": "[trimmed-depth]"
},
"report_url": "https://www.gdacs.org/report.aspx?eventid=1104019&episodeid=2&eventtype=FL",
"distance_km": 150
},
{
"event_id": 1104024,
"episode_id": 1,
"type": "flood",
"type_code": "FL",
"name": "[redacted-name]",
"alert_level": "green",
"alert_score": 1,
"severity": 0,
"severity_text": "Magnitude 0 ",
"country": "Czech Republic",
"iso3": "CZE",
"from": "[redacted-phone]T01:00:00",
"to": "[redacted-phone]T01:00:00",
"is_current": true,
"coordinates": {
"lat": "[trimmed-depth]",
"lon": "[trimmed-depth]"
},
"report_url": "https://www.gdacs.org/report.aspx?eventid=1104024&episodeid=1&eventtype=FL",
"distance_km": 275.1
},
{
"event_id": 1104025,
"episode_id": 1,
"type": "flood",
"type_code": "FL",
"name": "[redacted-name]",
"alert_level": "green",
"alert_score": 1,
"severity": 0,
"severity_text": "Magnitude 0 ",
"country": "Poland",
"iso3": "POL",
"from": "[redacted-phone]T01:00:00",
"to": "[redacted-phone]T01:00:00",
"is_current": true,
"coordinates": {
"lat": "[trimmed-depth]",
"lon": "[trimmed-depth]"
},
"report_url": "https://www.gdacs.org/report.aspx?eventid=1104025&episodeid=1&eventtype=FL",
"distance_km": 294.6
}
],
"count": 3,
"days": 7,
"radius_km": 300,
"window_truncated": {
"earthquake": true,
"tropical_cyclone": false,
"flood": false,
"volcano": false,
"wildfire": true,
"drought": false
}
},
"risk_summary": {
"level": "moderate",
"score": 1,
"reasons": [
"official warning: heavy thunderstorms with gale- or storm-force gusts, heavy rain and hail",
"official warning: heavy rain",
"official warning: gale-force gusts"
],
"confidence": "high"
},
"sources": {
"weather": {
"source": "MET Norway Locationforecast 2.0",
"source_url": "https://api.met.no",
"license": "CC BY 4.0",
"source_updated_at": "[redacted-phone]T17:16:09Z",
"fetched_at": "[redacted-phone]T17:20:45Z",
"staleness_minutes": 4,
"stale": false,
"confidence": "high"
},
"air_quality": {
"source": "OpenAQ v3",
"source_url": "https://openaq.org",
"license": "per-source (attribution required)",
"source_updated_at": "[redacted-phone]T16:00:00Z",
"fetched_at": "[redacted-phone]T17:20:47Z",
"staleness_minutes": 80,
"stale": false,
"confidence": "high"
},
"alerts": {
"source": "EUMETNET MeteoAlarm",
"source_url": "https://meteoalarm.org",
"license": "CC BY 4.0",
"source_updated_at": "[redacted-phone]T16:31:00+00:00",
"fetched_at": "[redacted-phone]T17:20:50Z",
"staleness_minutes": 49,
"stale": false,
"confidence": "high"
},
"hazards": {
"source": "GDACS (EC-JRC/UN OCHA)",
"source_url": "https://www.gdacs.org",
"license": "open data, source acknowledgment",
"source_updated_at": null,
"fetched_at": "[redacted-phone]T17:20:47Z",
"staleness_minutes": 0,
"stale": false,
"confidence": "high"
}
},
"attribution": [
"Weather data by the Norwegian Meteorological Institute (MET Norway), CC BY 4.0 — https://api.met.no",
"Air-quality measurements via OpenAQ (openaq.org); underlying data licensed by each originating source (attribution required)",
"Alert data © EUMETNET MeteoAlarm (meteoalarm.org), CC BY 4.0 — time-delayed redistribution; may be incomplete or outdated; NOT the official source"
],
"disclaimer": "Informational only — NOT for life-safety decisions. Always follow your national meteorological/civil-protection authority for warnings."
}
}What the Weather & Hazards API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| environment_current | premium combined snapshot: current weather + AQ + active alerts + nearby hazards + risk_summary{level,reasons,confidence} for a coordinate | Ops teams call environment_current to get premium combined snapshot. | lat, lon, units, include, radius_km |
| forecast | global point forecast (MET Norway, ~9 days): hourly steps + daily aggregates with normalized weather-code, feels-like, sunrise/sunset/moon. Optional source=us_nws returns the US-official National Weather Service forecast for US coordinates (api.weather.gov, public domain) | Developer tools call forecast to get global point forecast (MET Norway, ~9 days). | lat, lon, units, hours, days, ... |
| air_quality | nearest-station air quality (OpenAQ v3): pollutants + computed AQI-US/EAQI-EU + station distance + measurement freshness; honest insufficient_data when no station | Validation workflows call air_quality to get nearest-station air quality (OpenAQ v3). | lat, lon, radius_km |
| alerts | official severe-weather warnings by country/US-state or coordinate: EU MeteoAlarm (39 countries) AND US NWS (api.weather.gov, all 50 states + territories + marine zones, via Webshare). The source is chosen automatically from the location; coverage/coverage_note name exactly which authority answered | Data-quality teams call alerts to get official severe-weather warnings by country/US-state or coordinate. | country, lat, lon, severity_min, active_only, ... |
| hazards_nearby | GDACS multi-hazard events (earthquake/cyclone/flood/volcano/wildfire/drought) within a radius of a coordinate, distance-sorted | Ops teams call hazards_nearby to get gDACS multi-hazard events (earthquake/cyclone/flood/volcano/wildfire/drought) within a radius…. | lat, lon, radius_km, days, types, ... |
| disasters | global GDACS disaster events with type/alert-level/date/bbox filters, or a single-event detail via event_id+event_type | Developer tools call disasters to get global GDACS disaster events with type/alert-level/date/bbox filters, or a single-event detai…. | types, min_alert_level, days, bbox, country, ... |
| earthquakes | USGS earthquake catalog (earthquake.usgs.gov, public domain): filter by magnitude, radius, time window, depth, and PAGER alert — includes small and medium-magnitude events that disaster aggregators like GDACS omit. Results are distance-sorted around a coordinate. Pass event_id for a single-event detail. | Validation workflows call earthquakes to get uSGS earthquake catalog (earthquake.usgs.gov, public domain). | lat, lon, radius_km, min_magnitude, max_magnitude, ... |
| natural_events | NASA EONET natural-event catalog (eonet.gsfc.nasa.gov, NASA open data): wildfires, severe storms, volcanoes, floods, icebergs, dust/haze — a second independent hazard source alongside GDACS. Filter by category, status, and date range; optionally list the full EONET category taxonomy. | Data-quality teams call natural_events to get nASA EONET natural-event catalog (eonet.gsfc.nasa.gov, NASA open data). | category, status, days, bbox, limit, ... |
| fires | Live wildfire and thermal-anomaly hotspots from NASA FIRMS (firms.modaps.eosdis.nasa.gov, NASA open data): pixel-level VIIRS (375 m) and MODIS (1 km) near-real-time detections — the raw sensor data that disaster aggregators like GDACS and EONET do not include. Query by a coordinate radius or a bounding box; each hotspot includes brightness, Fire Radiative Power (FRP), confidence, day/night flag, and the exact acquisition timestamp. | Ops teams call fires to get live wildfire and thermal-anomaly hotspots from NASA FIRMS (firms.modaps.eosdis.nasa.gov, NAS…. | lat, lon, radius_km, bbox, sensor, ... |
| geocode | Place name → coordinates (Open-Meteo Geocoding, GeoNames-backed, free/keyless): turns a city/town/region name into the lat/lon every other weather-intel action needs, with country, region (admin1/2), population, timezone and elevation. Pass 'id' (a GeoNames id from a prior result) for the single canonical record instead of a name search. | Developer tools call geocode to get place name → coordinates (Open-Meteo Geocoding, GeoNames-backed, free/keyless). | name, id, language, count |
| historical | Historical weather (Open-Meteo Archive / ERA5 reanalysis, 1940→present, free/keyless) for a coordinate and date range: daily aggregates (min/max temp, precipitation, wind, weather-code, sunrise/sunset) and/or hourly variables. The live forecast actions exclude history — this is the long-record companion. Default daily set is returned when neither 'daily' nor 'hourly' is specified. | Validation workflows call historical to get historical weather (Open-Meteo Archive / ERA5 reanalysis, 1940→present, free/keyless) for a c…. | lat, lon, start_date, end_date, units, ... |
| marine | Marine / ocean-wave forecast (Open-Meteo Marine, free/keyless) for a coordinate: significant wave height, period and direction plus swell and wind-wave components — hourly out to several days, plus daily maxima and the current sea state. On land (no marine grid cell) values are honestly null (never fabricated). | Data-quality teams call marine to get marine / ocean-wave forecast (Open-Meteo Marine, free/keyless) for a coordinate. | lat, lon, units, forecast_days, hourly, ... |
| air_quality_forecast | Air-quality FORECAST + pollen (Open-Meteo Air-Quality, CAMS-backed, free/keyless) for a coordinate: hourly forecast of PM2.5/PM10/O3/NO2/SO2/CO, the European AQI and US AQI, plus European pollen (alder/birch/grass/olive/ragweed/mugwort). Complements the OpenAQ nearest-station `air_quality` (which is measured, current only) with a forward forecast and pollen — and needs NO API key. Pollen is European-domain only; outside Europe it is honestly null. | Ops teams call air_quality_forecast to get air-quality FORECAST + pollen (Open-Meteo Air-Quality, CAMS-backed, free/keyless) for a coord…. | lat, lon, forecast_days, hourly, current |
Call environment_current from your stack
curl -X POST https://api.reefapi.com/weather-intel/v1/environment_current \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"lat":52.52,"lon":13.405}'import requests
r = requests.post(
"https://api.reefapi.com/weather-intel/v1/environment_current",
headers={"x-api-key": REEF_KEY},
json={
"lat": 52.52,
"lon": 13.405
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/weather-intel/v1/environment_current", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"lat": 52.52,
"lon": 13.405
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.weather-intel.environment_current with {"lat":52.52,"lon":13.405}.Who uses this API and why
- Weather apps call environment_current and forecast to show conditions.
- Logistics uses alerts and hazards_nearby to route around severe weather.
- Risk tools use disasters and earthquakes to monitor exposure.
Questions developers ask before integrating
Are the timestamps UTC or local?
It depends on the action, so read the string rather than assuming. A forecast for Istanbul returned current.time "2026-08-26T22:00:00Z" and every hourly step in UTC, while the daily buckets carry date_basis "solar-approx UTC+2" because a calendar day is grouped around local solar time. historical returns "2024-01-01T05:28" with no zone at all, and source=us_nws returns "2026-08-26T17:00:00-04:00". geocode gives you the IANA timezone for the point if you need to convert.
What does units=imperial actually change?
Temperature, wind speed and precipitation only. The same New York coordinate returned temperature 23.6 with wind in m/s under metric and temperature 75.4 with wind_speed 11.2 mph under imperial. Pressure stays pressure_hpa in both, humidity stays a percentage, and the field name never changes, so you cannot infer the unit from the key. On historical the daily_units block is authoritative and reports km/h for wind and cm for snowfall.
How far ahead does forecast go, and how fine is each step?
hours accepts 1 to 90 and days accepts 1 to 10. The steps are hourly for roughly the first 2.5 days and then 6-hourly out to about day 9, so step 40 is not 40 hours away. Each step carries its own timestamp and you should read that rather than counting. Daily aggregates include a samples count, 24 for a fully covered day, which drops for the partial first and last days.
How do I tell whether the data is stale?
Every response carries a source block. A measured MET Norway forecast showed source_updated_at 19:16Z against fetched_at 22:43Z, staleness_minutes 207, stale false and confidence medium. The same field set on the NWS path read staleness_minutes 45 with confidence high, and the MeteoAlarm feed read 551. Log staleness_minutes rather than the time you made the call.
Why do the pollutants in one air_quality response come from different places?
Because each pollutant is taken from the nearest station that actually reports it. A London lookup with radius_km 25 returned pm25 from Tower Hamlets at 6.15 km, pm10 from Camden at 1.68 km and no2 from Marylebone Road at 2.53 km, while nearest_station_km 1.68 describes the closest station overall rather than the source of any one value. Each pollutant carries its own station, station_distance_km, provider and age_hours, and that pm10 reading was 142.7 hours old while pm25 was 1.7. stale_readings_skipped counts what was dropped before those survivors were chosen.
Why did alerts come back with count 0 when there are clearly warnings?
active_only defaults to true, which keeps only warnings where onset is at or before now and expires is still ahead. A measured German call returned 7 warnings with active_only false and 0 with the default, because every warning in that snapshot had already expired and the feed's source_updated_at was 551 minutes old. Set active_only false to see the full feed and apply your own window against expires.
In earthquakes, what is the difference between a null field and a zero?
A magnitude 5.8 event near Toride returned felt_reports 153, cdi 5.7, mmi 4.624 and pager_alert "green". A magnitude 4.4 event 340 km away returned all four as null. Null means USGS never computed the value, usually because nobody filed a felt report, and it is not the same as zero shaking. tsunami is a genuine boolean, and status is "reviewed" or "automatic", which tells you whether a human has checked the solution.
What happens if I call marine for a point on land?
You get ok true, the full hourly array, and every wave field null, plus an on_land_note saying the coordinate is outside the ocean-wave grid and that nothing was fabricated. Berlin returned 24 rows of nulls. A point at 40.5, -70.0 in the Atlantic returned wave_height 0.98 m with wave_period 6.25 s and a current sea state. Check for a non-null wave_height rather than for an empty array.
What is the Weather & Hazards API?
Weather & Hazards API is a ReefAPI endpoint group for weather & hazards It returns live JSON through POST requests under /weather-intel/v1.
Is the Weather & Hazards API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. Weather & Hazards calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Weather & Hazards login or account?
No login to Weather & Hazards is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Weather & Hazards data?
The page example is captured from a live environment_current call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Weather & Hazards API use?
Weather & Hazards actions currently cost 1-3 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Weather & Hazards from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call weather-intel actions with the same key, credit pool and JSON envelope used by normal REST requests.