The Department of Meteorological Services (DMS) Weather API provides programmatic read access to Uganda's official weather forecast data — daily, city, marine and seasonal forecasts, plus lookup/search endpoints and early warning alerts. The API follows REST conventions and returns JSON (alerts are also available as CAP-compliant XML — see Early Warnings).
https://wids.mwe.go.ug/api/v1
All endpoints below are relative to this base. Responses are application/json
unless noted otherwise (the CAP alert endpoints return XML).
Every /forecast/* and /search/* endpoint requires a bearer token. Pass it one of two ways:
Every JSON endpoint (forecast/search) wraps its payload the same way. Success responses put the actual result under data, with any endpoint-specific extras (counts, filters, issue dates) merged in alongside it:
Error responses (see Errors & Codes) always use status: "error" with a message string instead — there is no separate numeric code field in the body; check the HTTP status code itself.
Errors return the HTTP status below with a JSON body of {"status":"error","message":"..."}.
| HTTP Status | Meaning |
|---|---|
| 200 OK | Success |
| 401 Unauthorized | No token provided, token invalid, or token revoked |
| 403 Forbidden | Token doesn't have the forecast:read scope |
| 404 Not Found | No data available for the request (e.g. no approved forecast yet, or filter matched nothing) |
| 429 Too Many Requests | Daily rate limit exceeded for this token |
Each token has a configurable daily request limit, set when the token is created in the API Portal. The limit resets at midnight, server local time (Africa/Kampala).
When a token has a limit configured, these headers are included on every response:
X-RateLimit-Remaining: 0. A token with no daily limit configured has no rate-limit headers at all.The latest approved daily forecast: overview, outlook text, and a period-by-period (4 periods/day) summary averaged across all regions.
/forecast/latest · Requires forecast:read
No query parameters.
The same latest approved forecast, broken down per region across all 4 periods — optionally narrowed to the region(s) containing a given district.
| Parameter | Type | Required | Description |
|---|---|---|---|
| district | string | optional | Partial district name. Resolves to that district's region(s) and returns only those; 404 if no district matches. |
Returns data.regions[], each with a periods[] array (4 entries). Meta includes region_count, filter_district, and matched_districts (only populated when district was passed).
The same latest approved forecast, with each response entry keyed by district rather than region. A district's forecast is inherited from its region's values (the underlying forecast is still produced per region), so this endpoint just saves callers the region → district resolution.
| Parameter | Type | Required | Description |
|---|---|---|---|
| district | string | optional | Partial district name. Omit to get every district (~137); 404 if the filter matches none. |
Returns data[] — one entry per district, each with district_id, district_name, region, and a periods[] array (4 entries). Meta includes district_count and filter.
The latest approved 5-day city forecast, for all cities or filtered to one.
| Parameter | Type | Required | Description |
|---|---|---|---|
| city | string | optional | Case-insensitive partial city name match. 404 if nothing matches. |
The latest approved Lake Victoria marine forecast, broken down per zone (wind, waves, visibility, hazard).
| Parameter | Type | Required | Description |
|---|---|---|---|
| landing_site | string | optional | Partial landing-site name — narrows to the zone(s) containing it. 404 if none matches. |
Returns data.zones[] with wind/wave/visibility/hazard fields plus matching icon URLs, alongside advisory_level and general_situation at the top level.
The latest issued seasonal forecast — overview, sector advisories, and a lightweight per-sub-region summary. Check in_season to see whether it actually covers the current month.
No query parameters. Returns the season's narrative fields (ITCZ, MJO, ENSO, Lake Victoria status), areas[] (per sub-region summary) and sector_advisories[].
in_season field before presenting it as current.Sub-region breakdown of the latest seasonal forecast: rainfall category, onset/peak/cessation dates, and the district list for each sub-region.
| Parameter | Type | Required | Description |
|---|---|---|---|
| district | string | optional | Matches against the sub-region's district list. 404 if none matches. |
Reference lookups for populating dropdowns — all require forecast:read.
| Endpoint | Optional filter | Returns |
|---|---|---|
| GET /search/regions | — | All regions, each with its districts nested inside |
| GET /search/cities | — | All registered cities |
| GET /search/landing_sites | zone_id integer | Marine landing sites, with district + zone context |
| GET /search/districts | sub_region_id integer, region string | Districts with their seasonal sub-region/region |
A separate, unauthenticated set of endpoints for active early-warning alerts, following the WMO Common Alerting Protocol (CAP) v1.2 standard. No token, no Authorization header — these are open by design so any aggregator can consume them.
https://wids.mwe.go.ug/api/v1/cap/* — not under the token-authenticated /forecast/* namespace above.| Endpoint | Format | Description |
|---|---|---|
| GET /cap/feed | application/atom+xml | Atom feed of all currently active, non-expired alerts. |
| GET /cap/latest | application/cap+xml | The single most severe active alert as CAP XML. 204 No Content if none are active. |
| GET /cap/{id} | application/cap+xml | CAP XML for one alert by ID. Cancelled alerts return a CAP Cancel message. |
| GET /cap/all | application/json | JSON list of active alerts with a cap_xml_url and public html_url per alert. |
Today there is a single scope. Every /forecast/* and /search/* endpoint requires it; a token missing it gets 403 Forbidden. The CAP alert endpoints need no scope or token at all.
| Scope | Applies to |
|---|---|
| forecast:read | All endpoints under /forecast/*, /search/* |
Every example below fetches the same thing — the current daily forecast — so you can compare languages directly.