Skip to main content

Forecast API

The Predict API provides site-level PM2.5 air quality forecasts generated by AirQo forecasting models. The service supports both daily forecasts (7-day horizon) and hourly forecasts (up to 168 hours / 7 days ahead by default). Forecasts can be retrieved for individual monitoring sites, grids, or cohorts of monitoring sites.

Tier requirement

Forecasts require a Premium Tier subscription.


Daily Forecasting Endpoint​

GET /api/v2/predict/daily-forecasting/

Returns PM2.5 forecasts for the next 7 days, grouped by monitoring site.

Supported Parameters​

ParameterDescription
site_idForecast for a single site
grid_idForecasts for all sites within a grid
cohort_idForecasts for all sites within a cohort
scopeOptional — "grid" or "cohort" to disambiguate when a scope ID could match either type

Only one of site_id, grid_id, or cohort_id may be provided per request.

Response Structure​

{
"success": true,
"data": {
"start_date": "2026-06-03",
"end_date": "2026-06-09",
"days": 7,
"total": 1,
"units": {
"pm2_5": "ug/m3",
"air_temperature": "degC",
"relative_humidity": "%",
"air_pressure_at_sea_level": "hPa",
"precipitation_amount": "mm",
"cloud_area_fraction": "%",
"wind_speed": "m/s",
"wind_from_direction": "degrees",
"wind_direction_compass": "compass",
"forecast_confidence": "%"
},
"forecasts": [
{
"site_details": {
"site_id": "64f7b3e8c9d25a0013f2d456",
"site_name": "Kampala Central",
"site_latitude": 0.3476,
"site_longitude": 32.5825
},
"forecasts": [
{
"date": "2026-06-03",
"forecast": {
"pm2_5_mean": 28.4,
"pm2_5_low": 22.1,
"pm2_5_high": 34.8,
"pm2_5_min": 19.0,
"pm2_5_max": 37.2,
"forecast_confidence": 84.5
},
"aqi": {
"aqi_category": "Moderate",
"label": "Air quality is acceptable for most people.",
"trend_message": "Air pollution may increase over the next 24 hours."
},
"met": {
"air_temperature": 24.7,
"relative_humidity": 72.1,
"air_pressure_at_sea_level": 1012.3,
"precipitation_amount": 0.0,
"cloud_area_fraction": 45.0,
"wind_speed": 3.2,
"wind_from_direction": 45,
"wind_direction_compass": "NE"
}
}
]
}
]
}
}

Hourly Forecasting Endpoint​

GET /api/v2/predict/hourly-forecasting/

Returns hourly PM2.5 forecasts beginning from the current forecast hour.

Supported Parameters​

ParameterTypeDescription
site_idstringForecast for a single site
grid_idstringForecasts for all sites within a grid
cohort_idstringForecasts for all sites within a cohort
scopestringOptional — "grid" or "cohort" to disambiguate
pageintegerPage number (default: 1)
limitintegerResults per page (default: 10, max: 100)

Only one of site_id, grid_id, or cohort_id may be provided per request.

What page/limit paginate

For a single site_id request, page/limit paginate the hourly forecast items for that site — total/total_pages reflect the count of hourly records across the full horizon. For a grid_id/cohort_id request, they instead paginate the sites in that scope — total/total_pages reflect the number of matching sites, and each page returns the full hourly horizon for the sites on that page.

Key Features​

  • Default forecast horizon: 168 hours (7 days)
  • Pagination support across all sites in a grid or cohort
  • AQI category, advisory label, and trend message included
  • Uncertainty range via pm2_5_q10 and pm2_5_q90 percentiles
  • Meteorological context included per hour

Response Structure​

{
"success": true,
"data": {
"start_timestamp": "2026-06-07T10:00:00+00:00",
"end_timestamp": "2026-06-14T10:00:00+00:00",
"hours": 168,
"page": 1,
"limit": 10,
"total": 168,
"total_pages": 17,
"units": {
"pm2_5": "ug/m3",
"air_temperature": "degC",
"relative_humidity": "%",
"air_pressure_at_sea_level": "hPa",
"precipitation_amount": "mm",
"cloud_area_fraction": "%",
"wind_speed": "m/s",
"wind_from_direction": "degrees",
"wind_direction_compass": "compass",
"forecast_confidence": "%"
},
"forecasts": [
{
"site_details": {
"site_id": "64f7b3e8c9d25a0013f2d456",
"site_name": "Kampala Central",
"site_latitude": 0.3476,
"site_longitude": 32.5825
},
"forecasts": [
{
"timestamp": "2026-06-07T10:00:00+00:00",
"forecast": {
"pm2_5_mean": 28.4,
"pm2_5_q10": 20.1,
"pm2_5_q90": 36.2,
"forecast_confidence": 84.5
},
"aqi": {
"aqi_category": "Moderate",
"label": "Air quality is acceptable for most people.",
"trend_message": "Air pollution may increase over the next hour."
},
"met": {
"air_temperature": 24.7,
"relative_humidity": 72.1,
"air_pressure_at_sea_level": 1012.3,
"precipitation_amount": 0.0,
"cloud_area_fraction": 45.0,
"wind_speed": 3.2,
"wind_from_direction": 45,
"wind_direction_compass": "NE"
}
}
]
}
]
}
}

Scope (Grid and Cohort) Forecasting​

When grid-based or cohort-based forecasting is requested, the API supports aggregated forecast retrieval through:

GET /api/v2/predict/hourly-forecasting/<scope_id>
GET /api/v2/predict/daily-forecasting/<scope_id>

The <scope_id> path parameter accepts a grid ID or cohort ID. Use the optional scope query parameter ("grid" or "cohort") if the ID is ambiguous.

The same scope metadata (scope, sites_count, sites_with_forecasts_count, site_names) is also included when you pass grid_id/cohort_id as a query parameter on the base endpoint — the path-parameter form above is just an alternative way to address the same request.

Scope Metadata Returned​

The fields below are returned inside the top-level data object ({ "success": true, "data": { ... } }).

{
"scope": {
"type": "grid",
"id": "64b7ac8fd7249f0029feca80",
"grid_id": "64b7ac8fd7249f0029feca80"
},
"sites_count": 3,
"sites_with_forecasts_count": 2,
"site_names": [
"Kampala Central",
"Makerere"
],
"forecasts": [
{
"site_details": {
"site_id": "68fca1da53b8b4001372887f",
"site_name": "Buyala 1 Mpigi",
"site_latitude": 0.313465,
"site_longitude": 32.405833
},
"start_date": "2026-06-03",
"end_date": "2026-06-09",
"days": 7,
"total": 7,
"forecasts": [
{
"date": "2026-06-03",
"forecast": {
"pm2_5_mean": 24.1,
"pm2_5_low": 18.0,
"pm2_5_high": 29.5
}
}
]
}
]
}

Response Field Reference​

Daily forecast item​

FieldTypeDescription
datestringForecast date (ISO 8601 date)
forecast.pm2_5_meannumberMean PM2.5 forecast in µg/m³
forecast.pm2_5_lownumberLower bound of forecast range
forecast.pm2_5_highnumberUpper bound of forecast range
forecast.pm2_5_minnumberMinimum predicted value across the day
forecast.pm2_5_maxnumberMaximum predicted value across the day
forecast.forecast_confidencenumberModel confidence (0–100%)
aqi.aqi_categorystringAQI category name (see AQI Categories below)
aqi.labelstringHealth advisory for this AQI level
aqi.trend_messagestringExpected direction of PM2.5 over the next period
met.air_temperaturenumberAir temperature in °C
met.relative_humiditynumberRelative humidity in %
met.air_pressure_at_sea_levelnumberAtmospheric pressure in hPa
met.precipitation_amountnumberExpected rainfall in mm
met.cloud_area_fractionnumberCloud cover in %
met.wind_speednumberWind speed in m/s
met.wind_from_directionnumberWind direction in degrees
met.wind_direction_compassstringWind direction as a compass point (e.g. "NE", "SW")

Hourly forecast item​

Same as daily, with the following differences:

FieldTypeDescription
timestampstringForecast hour (ISO 8601 datetime with timezone)
forecast.pm2_5_q10number10th percentile — lower uncertainty bound
forecast.pm2_5_q90number90th percentile — upper uncertainty bound

pm2_5_low / pm2_5_high are not included in hourly items; use pm2_5_q10 / pm2_5_q90 instead.


AQI Categories​

Forecasts include an AQI category derived from the predicted PM2.5 mean value.

CategoryPM2.5 range (µg/m³)Color
Good≤ 9.1Green (#00e400)
Moderate> 9.1 – 35.49Yellow (#ffff00)
Unhealthy for Sensitive Groups> 35.49 – 55.49Orange (#ff7e00)
Unhealthy> 55.49 – 125.49Red (#ff0000)
Very Unhealthy> 125.49 – 225.49Purple (#8f3f97)
Hazardous> 225.49Maroon (#7e0023)

Validation Error​

Returned when more than one of site_id, grid_id, or cohort_id is provided in the same request.

{
"success": false,
"message": "Please specify only one of site_id, grid_id, or cohort_id.",
"data": {
"forecasts": []
}
}

Caching and Update Frequency​

Forecast results are cached server-side for about an hour. Forecasts themselves are regenerated once per day, so caching responses on your end for a similar window gives a good balance between API call volume and data freshness. See Best Practices → for caching guidance.