Skip to content
worldgovdata
Documentation / Core concepts

Core concepts

Authentication

One header, one credential, no handshake. Everything hard about API auth is absent here — which puts all of the risk in one place: where you keep the key.

Send your key as a Bearer token on every request that returns data. Metadata endpoints work without one.

Every metered request

Authorization: Bearer wgd_live_7k2m9xq4b3dv_Yb2Nq…

There is no other accepted form. A key in a query string, a cookie, or a custom header is ignored, and the request is treated as anonymous — which on a billable route means 401 unauthorized. Putting credentials in a URL is how they end up in access logs, browser history and referrer headers, so we simply do not read them there.

Check a key

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

/v1/ping is free and returns the key id, its scopes and your balance. It is the right health check for a deployment: it proves the credential resolves without spending anything.

When you do not need a key

The catalogue is deliberately open. These routes answer without any credentials, so a crawler can index them and the portal can serve them:

  • GET /v1/countries — the country spine
  • GET /v1/indicators and GET /v1/indicators/{id} — the catalogue and one indicator’s metadata
  • GET /v1/topics — the taxonomy
  • GET /v1/meta/freshness and GET /v1/meta/coverage

Anonymous callers are rate-limited by IP address at the lowest tier — 30 requests a minute, 1,000 a day. Sending a key on these routes costs nothing and raises those ceilings, so there is no reason not to.

Everything that returns observation rows — /v1/data, /v1/rankings and country detail — requires a key. Without one they return 401 unauthorized.

Key format

Anatomy

wgd_live_<12-char id>_<40-char secret>
The four segments of an API key
SegmentExampleMeaning
prefixwgdIdentifies the credential as ours — useful to secret scanners.
environmentlivelive or test. Both are real credentials against the real data; see below.
id7k2m9xq4b3dv12 characters of Crockford base32 (no i, l, o or u). Not a secret — safe to log, and it is how we look the key up.
secret40 charactersAlphanumeric. Only a SHA-256 digest of this is stored. Shown once, never retrievable.

The id is inside the key by design. It lets us find the row with an indexed point lookup and then compare the secret in constant time — no table scan, and no timing signal that would let someone probe the key space. It also means support can help you with a key id without ever seeing a secret.

Your account page shows each key’s id and the last four characters of its secret. That is enough to tell two keys apart in a log without either being reconstructable.

Environments

The second segment of a key names its environment. Today every key created from the account page is live; test is recognised by the API and reserved for a non-production credential we have not yet exposed. There is no environment choice at creation time, so if your key says live, that is expected.

Until then, get the same benefit from naming: one key per deployment, each named after the thing that holds it. A key called staging appearing in production logs is just as visible as a prefix would have been, and revoking it costs you one environment rather than all of them.

Scopes

Every key is minted with a single scope, read, and every public endpoint needs exactly that. There is nothing to configure and nothing to choose at creation time.

The mechanism exists for what comes later. If a route ever requires a scope your key does not carry, it answers 403 key_scope rather than serving a partial result — and a key minted before that scope existed is refused rather than quietly upgraded, which is the safe direction.

Rotation and revocation

Rotating without downtime

There is no rotate button, because you do not need one. Keys are independent: create the new one, deploy it, then revoke the old one. At no point is there a window where neither works.

  • Create a second key and name it for the rollout — the account page allows 10 active keys.
  • Ship it to your environment and confirm with a call to /v1/ping.
  • Watch the old key’s last used timestamp on the account page. When it stops moving, nothing is still using it.
  • Revoke the old key.

What revocation does

Immediately and permanently. The next request presenting that key gets 401 invalid_key — no grace period, no cached acceptance, no way to un-revoke it. Revocation is the correct first move whenever you are unsure; a new key is twenty seconds away.

Missing credentials · 401

HTTP/1.1 401 Unauthorized

{
  "error": {
    "code": "unauthorized",
    "message": "Authentication required"
  }
}

Note that a revoked key, an expired key, a mistyped key, a key on a suspended account and a key that never existed all return the same invalid_key. Distinguishing them in the response would only help someone guessing at keys. Your side of it is simple: whatever the cause, the fix is to check the credential you deployed.

Expiry

A key may be given an expiry when you create it. After that moment it behaves exactly like a revoked key. Keys with no expiry never expire. An expiry is worth setting for anything short-lived — a contractor, a one-off migration, a demo — because it fails safe if everyone forgets.

Never put a key in client-side code

This is the one way to lose a key, and it is worth being blunt about. A key in a browser bundle, a mobile app, a notebook you share, or a public repository is a key that belongs to everybody who can read it.

The safe pattern

Call the API from your own server and let the browser call your server. The key never leaves your infrastructure, and you get three things you would otherwise have to build: a cache, a place to enforce your own limits, and one point at which to rotate.

Server-side proxy

Browser  ──▶  your backend  ──▶  https://api.worldgovdata.com/v1
                    ▲
                    └── WGD_API_KEY lives here, and only here

Add a cache to that proxy. Authenticated responses come back private, no-store — they carry your balance, so no shared cache may hold them — but a cache inside your own service is yours to control, and it will usually cut your credit spend by more than the proxy costs to run.

The rest of the rules

  • Environment variables, not source. Read WGD_API_KEY at runtime. Add .env to .gitignore before you write the key into it, not after.
  • Never in a URL. Query strings land in access logs, proxy logs, browser history and Referer headers. We do not read keys from them, so this cannot even work by accident.
  • Never in a notebook you publish. Jupyter saves cell output. Set the variable in the shell that launched the kernel.
  • Never in a CI log. Register it as a masked secret so an accidental env dump does not print it.
  • Never in a screenshot or a support ticket. Send the key id — the twelve-character middle segment. It is not secret and it is all we need.
  • One key per deployment. Shared keys make revocation an outage; separate keys make it a shrug.

If a key leaks

Revoke it first and investigate second. Revocation takes effect on the next request, so there is nothing to gain by waiting until you have worked out how far it spread. Then create a replacement, deploy it, and check your usage for requests you cannot account for. If the numbers look wrong, tell us — the key id is enough for us to trace it.