Developers

Kuramap API

A read-only JSON API over Kenya's counties, constituencies and wards - and the people who currently represent each one. Call it anonymously, or with a free API key for a higher, attributable quota.

Before you build on it, read where the data comes from and what's known to be wrong with it - it also carries the licence and attribution terms for reuse.

Getting started

  1. Sign up

    Go to the developer dashboard and enter your email. We send a one-time magic link - no password.

  2. Create a key

    From the dashboard, choose Create key. Your key is shown exactly once - copy it now. We store only a hash and the non-secret prefix (km_live_<id>), so we can't show it again. Lost it? Revoke and create another.

  3. Make your first request

    Pass the key as a bearer token. (Drop the header for anonymous, cacheable access.)

    curl -sS \
      -H "Authorization: Bearer km_live_3f9a1c20…" \
      https://kuramap.euxven.com/api/v1/ke/counties/nairobi
  4. Mind the rate limits

    The free tier allows 10,000 requests/day with a 600 requests/minute burst. Every keyed response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds to the next 00:00 UTC reset). Over the limit returns 429 with a Retry-After header - back off and retry.

Client snippets

JavaScript (fetch)

const res = await fetch(
  "https://kuramap.euxven.com/api/v1/ke/representatives?role=governor&region=nairobi",
  { headers: { Authorization: "Bearer km_live_3f9a1c20…" } },
);
if (res.status === 429) {
  const retry = res.headers.get("Retry-After");
  throw new Error(`Rate limited; retry after ${retry}s`);
}
const page = await res.json();
console.log(page.items, "of", page.total);

Python (requests)

import requests

resp = requests.get(
    "https://kuramap.euxven.com/api/v1/ke/lookup",
    params={"lat": -1.2921, "lng": 36.8219},
    headers={"Authorization": "Bearer km_live_3f9a1c20…"},
    timeout=10,
)
resp.raise_for_status()
print(resp.headers.get("X-RateLimit-Remaining"), "requests left today")
print(resp.json()["ward"]["name"])

Versioning & deprecation

The API is versioned in the path: /api/v1. Within v1 we only make backward-compatible changes - new endpoints, new optional query parameters, and new fields on existing objects. Write your client to ignore unknown fields and unknown enum values so these additions never break you.

A breaking change - removing or renaming a field, changing a type, or altering response semantics - would ship under a new major path (/api/v2), running alongside v1. Anything slated for removal is marked deprecated here first, with a published sunset window, before it is withdrawn.

API reference

The full, generated reference - every endpoint, parameter and schema - lives on its own page. You can also fetch the raw spec at /openapi.yaml (OpenAPI 3.1).

Open the API reference