Skip to content
worldgovdata
Documentation / Endpoints

Endpoints

Endpoint reference

Eleven routes, all GET, all under one base URL. Six of them have a page of their own; the two account-facing utilities are documented here.

Base URL

https://api.worldgovdata.com/v1

An anonymous response

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=3600, s-maxage=21600
X-Request-Id: 0f3a91c4e2b7

# No X-Credits-* and no X-RateLimit-*: this response is identical for
# every caller, which is the whole reason a shared cache may keep it.

Every route

Every public API route with its cost and auth requirement
RouteCreditsKeyReturns
GET /v1/countriesfreeoptionalThe country spine.
GET /v1/countries/{iso3}1requiredOne country with every latest value it has.
GET /v1/indicatorsfreeoptionalThe catalogue. Search, filter, sort, page.
GET /v1/indicators/{id}freeoptionalOne indicator plus its related set.
GET /v1/topicsfreeoptionalThe 13-topic taxonomy with counts.
GET /v1/meta/freshnessfreeoptionalPer-provider licence, cadence, last successful load.
GET /v1/meta/coveragefreeoptionalPer-country observation and indicator counts.
GET /v1/rankings/{indicator}1requiredEvery country ranked on one indicator, one year.
GET /v1/datamax(1, ceil(rows / 100))requiredRaw observations, JSON or CSV. The only variable price.
GET /v1/usagefreerequiredYour own balance and recent usage.
GET /v1/pingfreerequiredKey liveness: key id, scopes, balance.

optional means the route answers without credentials, rate-limited by IP at the anonymous tier. Sending a key costs nothing and raises those limits. required means no key, no answer: 401 unauthorized.

Reference pages

The two account routes

Both are free, and both need a key — they are about your account, so they have to know whose it is. Neither has a reference page of its own because neither takes a parameter.

GET /v1/ping

The liveness check for a deployment. It confirms the key resolved and reports the key id, the scopes it carries, your rate-limit tier and your balance. It costs nothing and touches no data — the balance comes from the key resolution that already happened — so it is the right thing to call at boot to fail fast on a bad credential.

Request

curl -sS "https://api.worldgovdata.com/v1/ping" -H "Authorization: Bearer $WGD_API_KEY"

Response · 200

{
  "data": {
    "ok": true,
    "key_id": "7k2m9xq4b3dv",
    "scopes": ["read"],
    "tier": "paid",
    "credits_remaining": 24998
  },
  "meta": {
    "generated_at": "2026-07-28T09:14:02.481932+00:00"
  }
}

tier is anonymous, free or paid — the same three tiers on Rate limits. Seeing anonymous on a key you just made means the account has not verified its email address yet.

A 401 invalid_key means the credential was read and rejected — unknown, malformed, revoked, expired or closed account, all one code on purpose. A 401 unauthorized means you sent nothing at all.

GET /v1/usage

Your own balance and recent usage, for the key making the call. Free, and the one way to watch your own burn rate from a script without a browser session.

Response · 200

{
  "data": {
    "credits": {
      "user_id": "3f5b1c40-1d2e-4a77-9c31-8e0b6a2d4f11",
      "balance": 24998,
      "lifetime_granted": 27000,
      "lifetime_spent": 2002,
      "updated_at": "2026-07-28T08:52:17.104882+00:00"
    },
    "totals": { "requests": 1841, "credits": 2002, "errors": 12, "days": 30 },
    "daily": [
      { "day": "2026-06-29", "requests": 0,   "credits": 0,   "errors": 0 },
      { "day": "2026-06-30", "requests": 214, "credits": 260, "errors": 2 },
      // … one entry for every day in the window, including the empty ones
      { "day": "2026-07-28", "requests": 96,  "credits": 118, "errors": 0 }
    ],
    "endpoints": [
      { "endpoint": "/v1/data",       "requests": 902, "credits": 1974, "errors": 9 },
      { "endpoint": "/v1/rankings/{indicator}", "requests": 28, "credits": 28, "errors": 0 },
      { "endpoint": "/v1/indicators", "requests": 911, "credits": 0,    "errors": 3 }
    ]
  },
  "meta": {
    "generated_at": "2026-07-28T09:14:02.481932+00:00",
    "days": 30,
    "key_id": "7k2m9xq4b3dv"
  }
}
  • days — the only parameter. An integer from 1 to 90, defaulting to 30. Today counts as one of them, so days=1 means today. The window actually used is echoed in meta.days.
  • credits — the wallet: current balance plus lifetime_granted and lifetime_spent.
  • totals — the window folded into one row, summed from the same series returned below it, so the headline and the chart cannot disagree.
  • dailydense: every day in the window appears, oldest first, zero-filled where nothing happened. Plot it without gap-filling.
  • endpoints — per-route totals, busiest first, and deliberately not zero-filled. Routes you have never called are absent rather than listed at zero.

Endpoints are reported as route templates /v1/rankings/{indicator}, never the path you actually called. Raw paths carry query strings and query strings carry intent, which is not something worth retaining.

Behaviour every route shares

  • GET only. The public API is read-only. Anything else returns 405 method_not_allowed.
  • Two-key envelope. Success is { "data": …, "meta": … }; failure replaces the body with { "error": { "code", "message" } }. meta.generated_at is always present.
  • meta echoes your filters, and omits anything you did not send. An absent key means “not applied”, never “null”.
  • The licence gate applies everywhere. An indicator we may not redistribute is not listed, not ranked and not retrievable — it does not exist as far as the API is concerned. See Licensing.
  • Caching depends on who asked. An anonymous GET returns public, max-age=3600, s-maxage=21600; an authenticated one returns private, no-store; any error returns no-store. Cache in your own application regardless — a response you did not re-request costs no credit and no quota.
  • Per-caller headers only on authenticated calls. X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Credits-Charged, X-Credits-Remaining are withheld from anonymous responses, precisely because those are the ones a shared cache may keep. X-Request-Id is on everything.
  • Nulls are real. value, ci_lo, ci_hi, rank and most coverage fields are nullable. A missing measurement is a null, not a zero and not an absent row.

Identifier conventions

  • Countries are ISO 3166-1 alpha-3: IND, CHN, USA. Case is normalised for you, so /v1/countries/ind and /v1/countries/IND are the same request. In a comma-separated list, whitespace around a code is trimmed.
  • Indicators are provider.slugwgi.control_of_corruption, wdi.gdp_per_capita_ppp. These are case-sensitive and exact; there is no fuzzy resolution. Find one with /v1/indicators?q=…, which is free.
  • Years are four-digit integers. from and to on /v1/data are both inclusive.
  • Topics are lowercase slugs — governance, economy, health. Ask /v1/topics rather than hardcoding the list.