Skip to content

API access

Programmatic access, on request.

A read-only JSON and CSV API over the same data the Observatory shows. Reading the website (the charts and tables) and downloading from it never need a key. To call the API from your own code, including to fetch CSV or Excel through it, ask for a key.

How to get access

Three steps

  1. 1

    Email your request

    Say who you are, what you will use the data for, and which data you need. A short note is enough.

  2. 2

    Receive a key

    Access is granted case by case. You get a personal key with an expiry date.

  3. 3

    Call the API

    Send the key as an X-API-Key header, with the same endpoints below. Cite the source when you publish.

The button opens your email program with a short form already filled in, so nothing is sent until you press send.

Using your key

An example request

curl -H "X-API-Key: tdo_YOUR_KEY" \
  "https://YOUR-OBSERVATORY-HOST/api/v1/series?ids=Revenue_by_TaxHead:4&from=2018/19"

// or from code
const res = await fetch("https://YOUR-OBSERVATORY-HOST/api/v1/series?ids=Revenue_by_TaxHead:4", {
  headers: { "X-API-Key": "tdo_YOUR_KEY" },
});
const { series } = await res.json();
// series[0].points → [{ fy: "2015/16", value: 11230.87 }, …]
// series[0].flags  → known data-quality notes for this indicator

Without a valid key the API answers 401 with a message telling you how to ask. Keys can be cancelled early; an expired or cancelled key is refused.

Endpoints

What you can ask

GET /api/v1/sheets

The 14 sheets with coverage, sections and source notes; add ?sheet=<name> for one sheet with all its indicators.

Parameters: sheet

/api/v1/sheets?sheet=Enforcement

GET /api/v1/catalog

Search indicators across every sheet and the Macro Data Portal.

Parameters: q, sheet, source=ura|portal, limit

/api/v1/catalog?q=arrears&limit=10

GET /api/v1/series

One or more series by id, as JSON (with their data-quality flags) or CSV.

Parameters: ids, from, to, format=json|csv

/api/v1/series?ids=Revenue_by_TaxHead:4&from=2018/19

GET /api/v1/observations

Long-format rows: one per indicator per fiscal year. Paged.

Parameters: q, sheet, section, id, from, to, limit (≤1000), offset, format=json|csv

/api/v1/observations?sheet=Customs_Trade&q=exports&limit=20

GET /api/v1/districts

District-level counts from the URA workbook (new TIN registrations, presumptive tax register) for every district, with the published total.

Parameters: set (newtin, presumptive)

/api/v1/districts?set=newtin

GET /api/v1/sources

Where the data comes from: the URA dataset and the Uganda Macro Data Portal snapshot (datasets, publishers, dates).

Parameters: none

/api/v1/sources

GET /api/v1/sections

The sections of one sheet with their indicator ids, and which are reconciled to a published total.

Parameters: sheet

/api/v1/sections?sheet=Audit_Enforcement

GET /api/v1/dictionary

The data dictionary: unit, description and source reference for each indicator.

Parameters: q, sheet

/api/v1/dictionary?q=arrears

GET /api/v1/health

Blank counts per sheet, reconciliation results and the catalogue of known data-quality flags.

Parameters: none

/api/v1/health

Conventions

Ids, years and blanks

  • Ids. An indicator id is <sheet>:<source row>, for example Revenue_by_TaxHead:4 (Net URA Collections); Macro Data Portal series look like mdp:BOU_MMI_FY:E_EP. Find ids with the catalogue.
  • Fiscal years. Strings such as 2015/16 (July to June). EFRIS also carries a Pre-2019/20 (Undated) bucket.
  • Blanks. A blank cell in the source is simply absent from a series. It is not zero, and nothing is interpolated.

Source: Uganda Revenue Authority Annual Data Books; Uganda Bureau of Statistics (GDP, trade); and the Uganda Macro Data Portal. Please cite what you use: see how to cite. Check the data quality page before relying on a flagged series.