AkadaIQ API Reference

Nigeria's Education Trust Infrastructure — the verified registry of universities, polytechnics, and colleges of education, with EduKYC verification, AI-native access, and provenance on every field.

REST · JSON v1 MCP compatible provenance on every response

Introduction

The AkadaIQ API answers one family of questions with audit-grade confidence: which Nigerian higher institutions exist, what is their current legal and regulatory status, and can you prove it? It serves four kinds of consumers:

ConsumerTypical usage
Lenders & fintech (student loans, KYC)POST /v1/verify/institution as a disbursement or onboarding gate; GET /v1/changelog for continuous monitoring
Edtech & admission platformsGET /v1/search autocomplete, GET /v1/institutions filtering, POST /v1/admitiq/probability
HR & background-check servicesPOST /v1/verify/institution and POST /v1/verify/program for credential screening
AI agents & assistantsThe MCP server, or POST /v1/ask for grounded natural-language answers
Design commitment — honesty by default. AkadaIQ never invents data. Records seeded from compiled directories carry verified: false until re-confirmed by human curators against current NUC/NBTE/NCCE publications; verification verdicts disclose record status either way; endpoints return explicit data-gap notices instead of estimates. Build against those signals — they are load-bearing, not decorative.

Base URL & environments

https://akadaiq.com

All endpoints are versioned under /v1 (the MCP server lives at /mcp). HTTPS only. CORS is enabled on all endpoints (Access-Control-Allow-Origin: *), so browser-side calls work — but treat browser-exposed keys as public and scope them accordingly (see Best practices).

Sandbox access uses the same base URL with a sandbox-tier key issued by the AkadaIQ team — request one at partnerships@akadaiq.com.

Authentication

Every request requires an API key except the two open endpoints (/v1/stats, /v1/health). Pass the key in the x-api-key header (preferred) or as an api_key query parameter:

# Header (preferred)
curl "https://akadaiq.com/v1/search?q=unilag" \
  -H "x-api-key: ak_live_4f9c1d2e8b7a6f5e4d3c2b1a0f9e8d7c6b5a4f3e2d1c0b9a"

# Query parameter (for clients that cannot set headers, e.g. some MCP hosts)
curl "https://akadaiq.com/v1/search?q=unilag&api_key=ak_live_…"

Keys are prefixed ak_live_ and are shown once at creation. A missing key returns 401; a deactivated key returns 403; an exhausted daily quota returns 429. Keys are managed by the AkadaIQ team; enterprise accounts can request multiple keys with distinct names for per-system usage attribution — every verification is logged against the key that made it.

Response envelope

Every response — success or failure — is JSON in a consistent envelope:

// Success
{ "success": true, "data": { … } }

// Success with pagination (list endpoints)
{ "success": true, "data": [ … ],
  "pagination": { "page": 1, "per_page": 25, "total": 137, "total_pages": 6 } }

// Failure
{ "success": false, "error": { "code": 401, "message": "Invalid API key." } }

Always branch on the success boolean rather than HTTP status alone; the error.message is written to be actionable and safe to surface to your operators.

Errors

HTTPMeaningTypical cause & fix
400Bad requestMissing/invalid body field or query parameter. The message names the field.
401UnauthenticatedNo key, or key not found. Check the x-api-key header.
403ForbiddenKey deactivated, or endpoint requires a higher tier.
404Not foundUnknown endpoint or institution id. Use /v1/search to resolve ids.
405Method not allowedGET sent to a POST endpoint (verification, ask, AdmitIQ are actions, not pages).
429Rate limitedDaily quota reached for the key's tier. Resets at 00:00 UTC. Upgrade or retry tomorrow.
500Server errorRetry with exponential backoff; if persistent, contact support with the timestamp.

Tiers & rate limits

TierDaily requestsScope
free100Registry, search, verification, ask, AdmitIQ — evaluation use
growth10,000Full API for production edtech / platform use
verification50,000High-volume EduKYC workloads; per-check billing with audit reporting
enterpriseCustomSLA, webhooks, bulk export, dedicated support, custom deployment

Quotas are counted per key per UTC day. Current usage is visible to the AkadaIQ team per key; enterprise accounts receive usage reporting. There is no per-second throttle at present, but sustained bursts above ~10 req/s should be coordinated with support.

Quickstarts

curl

# 1. Find the institution's canonical id
curl "https://akadaiq.com/v1/search?q=covenant" -H "x-api-key: $AKADAIQ_KEY"

# 2. Pull the full record
curl "https://akadaiq.com/v1/institutions/covenant-university" -H "x-api-key: $AKADAIQ_KEY"

# 3. Run an EduKYC verification
curl -X POST "https://akadaiq.com/v1/verify/institution" \
  -H "x-api-key: $AKADAIQ_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Covenant University"}'

JavaScript (Node or browser)

const BASE = "https://akadaiq.com";
const KEY  = process.env.AKADAIQ_KEY;

async function verifyInstitution(name) {
  const res = await fetch(BASE + "/v1/verify/institution", {
    method: "POST",
    headers: { "Content-Type": "application/json", "x-api-key": KEY },
    body: JSON.stringify({ name })
  });
  const json = await res.json();
  if (!json.success) throw new Error(json.error.message);
  return json.data;   // { reference, verdict, … }
}

Python

import os, requests

BASE = "https://akadaiq.com"
HEADERS = {"x-api-key": os.environ["AKADAIQ_KEY"]}

def verify_institution(name: str) -> dict:
    r = requests.post(f"{BASE}/v1/verify/institution",
                      json={"name": name}, headers=HEADERS, timeout=30)
    body = r.json()
    if not body["success"]:
        raise RuntimeError(body["error"]["message"])
    return body["data"]

result = verify_institution("Atlanta University, Anyigba")
print(result["verdict"], result["reference"])   # ILLEGAL AKD-…

The institution record

Institutions are the core resource. The canonical id is a URL-safe slug (e.g. university-of-lagos, federal-polytechnic-nekede) that is stable across renames — a rename updates name and is announced in the changelog; the id persists.

FieldTypeDescription
idstringCanonical slug. Stable. Use this as your foreign key.
namestringCurrent official name.
acronymstring | nullCommon acronym (UNILAG, FUTA, LASU) where one exists.
typeenumuniversity · polytechnic · college_of_education
ownershipenumfederal · state · private
state, citystring | nullLocation (Nigerian state; host town/city).
regulatorenumNUC · NBTE · NCCE
statusstringactive in the normal case; proposed for announced-but-unconfirmed institutions.
year_established, website, jamb_code, logo_urlvarious | nullEnrichment fields, populated progressively by curation.
officers, campusesarrayKey officers and campus list, populated progressively.
coursesarrayProgramme records: name, degree, duration_years, cut_off_mark, accreditation_status, accreditation_history[], per-course provenance. Populated progressively — see the data-gap notes on each endpoint.
provenanceobjectSee Provenance. Present on every record; ships even under field selection.
needs_review, review_noteboolean, string | nullSet when a known change (rename, upgrade, relocation) is pending curator confirmation. Treat flagged records with extra care in compliance flows.

Provenance — the field that makes the rest trustworthy

Every record carries a provenance object, and it always ships — even when you use fields= selection. It answers three questions: where did this come from, when was it last confirmed, how confident are we?

"provenance": {
  "source":        "NUC directory of Nigerian universities",
  "source_date":   "2026-06",
  "verified":      true,          // re-confirmed by a human curator against the regulator
  "last_verified": "2026-07-03",
  "confidence":    "high"         // high | medium | low
}
verified: true — curator-confirmed against the current regulator directory verified: false — seeded/extracted, pending curator re-verification; treat as provisional

Recommended handling: for informational displays, show unverified records with a "provisional" indicator; for compliance gates, apply your own policy — many integrators accept verified: true automatically and route verified: false to manual review rather than rejecting.

Verdict semantics

Verification endpoints return one of a closed set of verdicts. Wire your decision logic to these exact strings:

VerdictMeaningSuggested action
RECOGNISEDConfident registry match; institution active under its regulator.Proceed. Record the reference and the returned provenance.
RECOGNISED_WITH_FLAGSMatched, but record status is not plain active (e.g. proposed).Manual review before high-stakes actions.
ILLEGALName matches the NUC illegal-institutions blacklist.Stop. Do not disburse/accept. Confirm against the current NUC publication as the response instructs.
NOT_FOUNDNo sufficiently confident match in registry or blacklist.Caution flag, not proof of illegitimacy. The response includes closest_matches — often the user misspelled; re-query or route to manual check against the regulator sites.
PROGRAM_ON_RECORDProgramme found; accreditation status returned (incl. at graduation year where history exists).Proceed per your accreditation policy.
PROGRAM_NOT_ON_RECORDInstitution is on record but course-level data isn't loaded yet.An honest gap, not a denial — verify the programme manually; institution-level verdict still stands.
GET/v1/institutionsAPI key

List and filter the registry. Returns paginated institution records sorted alphabetically, or by relevance when search is used.

Query paramTypeDescription
typeenumuniversity · polytechnic · college_of_education
ownershipenumfederal · state · private
statestringNigerian state, case-insensitive (e.g. Lagos, Akwa Ibom)
regulatorenumNUC · NBTE · NCCE
statusstringe.g. active, proposed
verifiedbooleantrue restricts to curator-verified records only
searchstringFuzzy match on name/acronym/town — handles Nigerian shorthand (Fed Poly Nekede, LASU Ojo, Ibadan Poly)
fieldscsvField selection, e.g. name,state,ownership. id and provenance always included.
page / per_pageintDefault 1 / 25; per_page max 100
# Federal universities in Lagos, minimal fields
curl "https://akadaiq.com/v1/institutions?type=university&ownership=federal&state=Lagos&fields=name,city" \
  -H "x-api-key: $AKADAIQ_KEY"
{ "success": true,
  "data": [
    { "id": "university-of-lagos", "name": "University of Lagos", "city": "Lagos",
      "provenance": { "source": "…", "verified": true, "last_verified": "2026-07-03", "confidence": "high" } }
  ],
  "pagination": { "page": 1, "per_page": 25, "total": 1, "total_pages": 1 } }
GET/v1/institutions/{id}API key

The full record for one institution — including courses, campuses, officers, review flags, and provenance. 404 with a hint to use /v1/search if the id is unknown.

curl "https://akadaiq.com/v1/institutions/covenant-university" -H "x-api-key: $AKADAIQ_KEY"
GET/v1/institutions/{id}/coursesAPI key

Programmes on record for one institution. Filters: name (substring), accreditation (exact status). Returns { institution, count, courses }.

GET/v1/coursesAPI key

Cross-institution programme search — "all accredited Pharmacy programmes in the South-West" style queries. Filters: name, state, type, accreditation, max_cutoff. Returns up to 200 hits, each annotated with institution_id, institution, state, ownership.

Data-gap behavior: course-level records populate progressively through Sentinel extraction and curator loading of JAMB-brochure and accreditation publications. An empty result includes an explicit note saying so — it means "not loaded yet," never "does not exist."

Autocomplete and name resolution — the front door of most integrations. Feed the returned id into everything else.

Query paramDescription
q (required)Partial name, acronym, or name+town. The matcher expands Nigerian shorthand: poly→polytechnic, uni/varsity→university, fed→federal.
limitMax results, default 8
curl "https://akadaiq.com/v1/search?q=fed%20poly%20nekede" -H "x-api-key: $AKADAIQ_KEY"
{ "success": true, "data": [
  { "id": "federal-polytechnic-nekede", "name": "Federal Polytechnic, Nekede",
    "acronym": "FPNO", "type": "polytechnic", "ownership": "federal",
    "state": "Imo", "match_score": 1 }
] }
GET/v1/statsopen

Registry totals by type, ownership, and regulator, plus verified_records and verification_coverage (the percentage of records curator-confirmed against current regulator directories). No key required — suitable for status pages and due-diligence checks.

GET/v1/healthopen

Deployment/uptime diagnostic: environment wiring, Firestore connectivity, and registry counts, with a status of READY or SETUP_INCOMPLETE and an actionable hint. Poll it from your monitoring.

GET/v1/changelogAPI key

The registry's audited change feed — every approved change (renames, upgrades, verifications, blacklist updates) in reverse-chronological order. This is how consumers stay in sync; see Keeping data fresh.

Query paramDescription
sinceISO-8601 timestamp; returns only changes after it (e.g. 2026-07-01T00:00:00Z)
limitMax entries, default 50, max 200
{ "success": true, "data": [
  { "change_id": "aB3xK…", "at": "2026-07-03T09:12:44.001Z",
    "kind": "record_verified", "institution_id": "covenant-university" },
  { "change_id": "pQ9mL…", "at": "2026-07-02T06:04:10.552Z",
    "kind": "sentinel_change_approved",
    "change": { "change_type": "upgrade", "institution_name": "…", "summary": "…" } }
] }
POST/v1/verify/institutionAPI key · billed per check

The EduKYC core. Screens the submitted name against the NUC illegal-institutions blacklist first, then resolves it against the registry with fuzzy matching. Every call mints a permanent audit reference (AKD-…) logged server-side with timestamp, verdict, and calling key.

Body fieldTypeDescription
name (required)stringInstitution name as received — do not pre-clean it; the matcher handles acronyms, shorthand, and town suffixes.

Response — ILLEGAL (real production example):

{ "success": true, "data": {
  "reference": "AKD-E86AA0FEB2EE",
  "verdict": "ILLEGAL",
  "headline": "This name matches an institution on the NUC illegal institutions list.",
  "matched": "Atlanta University, Anyigba, Kogi State",
  "blacklist_status": "illegal_closed",      // or "under_investigation"
  "match_confidence": 0.94,
  "guidance": "NUC states certificates from illegal institutions are not recognised…",
  "provenance": { … } } }

Response — RECOGNISED:

{ "success": true, "data": {
  "reference": "AKD-1A2B3C4D5E6F",
  "verdict": "RECOGNISED",
  "headline": "Covenant University is in the AkadaIQ registry as a private university regulated by NUC.",
  "institution": { "id": "covenant-university", "name": "Covenant University",
                   "type": "university", "ownership": "private", "state": "Ogun",
                   "city": "Ota", "regulator": "NUC", "status": "active" },
  "match_confidence": 1,
  "record_verified": true,
  "provenance": { … },
  "guidance": "Record verified against the NUC directory on 2026-07-03." } }

Response — NOT_FOUND includes closest_matches (id, name, score) so your UI can offer corrections. Remember: NOT_FOUND is a caution flag, not a denial.

POST/v1/verify/programAPI key · billed per check

Programme-level verification, including accreditation status in a specific graduation year where accreditation history is on record — the query no other Nigerian source can answer programmatically.

Body fieldTypeDescription
institution (required)stringInstitution name (fuzzy-resolved)
program (required)stringProgramme name, e.g. Pharmacy
graduation_yearintOptional. Adds accreditation_at_graduation when history exists.

Verdicts: PROGRAM_ON_RECORD (with current_accreditation and, if requested, accreditation_at_graduation) or PROGRAM_NOT_ON_RECORD (explicit gap notice — the institution-level result still stands). Both mint an audit reference.

POST/v1/askAPI key

Grounded natural-language queries. This is not a chatbot passthrough — it is a three-step auditable pipeline: (1) AI converts the question to a structured query plan, (2) the plan executes deterministically against the registry, (3) AI composes an answer from the returned records only, with data gaps stated plainly. The response includes the plan and records so every answer can be audited.

Body fieldDescription
question (required)Plain-language question. Geographic zones understood (South-West, North-Central, etc.). Out-of-scope questions are declined explicitly.
curl -X POST "https://akadaiq.com/v1/ask" -H "x-api-key: $AKADAIQ_KEY" \
  -H "Content-Type: application/json" \
  -d '{"question": "Which federal universities in the South-West are on record?"}'
{ "success": true, "data": {
  "answer": "The registry lists six federal universities in the South-West: University of Lagos, University of Ibadan, Obafemi Awolowo University…",
  "plan": { "intent": "list", "filters": { "type": "university", "ownership": "federal", "state": "zone:South-West" } },
  "total_matches": 6,
  "records": [ { "id": "university-of-lagos", … } ] } }
Latency note: /v1/ask makes two AI model calls and typically responds in 3–8 seconds. Use the structured endpoints for latency-sensitive paths; use /v1/ask for assistants, dashboards, and analyst tooling.
POST/v1/admitiq/probabilityAPI key

Admission intelligence, honest by construction: probability bands are computed only against cut-off figures on record — never estimated. Where no records exist yet, you receive a data_gap object with matching institutions and clearly-labeled general guidance.

Body fieldTypeDescription
utme_score (required)int 0–400Candidate UTME score
course (required)stringProgramme of interest
state, ownership, typestringOptional pool filters

Bands: STRONG (+40 or more above recorded cut-off) · COMPETITIVE (+15 to +39) · BORDERLINE (0 to +14) · BELOW_CUTOFF. The methodology field ships with every response; treat bands as directional — departmental and catchment adjustments are not yet modeled, and the response says so.

POST/mcpAPI key

AkadaIQ is a native Model Context Protocol server (stateless JSON-RPC 2.0 over Streamable HTTP), so AI assistants can use the registry as a tool. A GET on the endpoint returns a human-readable summary.

Connecting from Claude: Settings → Connectors → Add custom connector → URL https://akadaiq.com/mcp, passing your key via the x-api-key header if the client supports headers, or ?api_key=ak_live_… appended to the URL.

ToolArgumentsReturns
search_institutionsquery?, state?, type?, ownership?Up to 15 matches with verification status
get_institutionidFull record incl. provenance
verify_institutionnameRECOGNISED / ILLEGAL / NOT_FOUND with guidance
registry_statsAggregate landscape statistics
# Raw JSON-RPC example
curl -X POST "https://akadaiq.com/mcp" -H "x-api-key: $AKADAIQ_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"verify_institution","arguments":{"name":"UNESCO University Ndoni"}}}'

Supported methods: initialize, notifications/initialized, tools/list, tools/call, ping. Tool operations require the API key; initialize does not, so clients can handshake before auth.

Guide — keeping your copy fresh

If you cache registry data (recommended for latency), synchronize with the changelog rather than re-pulling everything:

// Nightly sync job
const since = await store.get("akadaiq_last_sync");           // ISO timestamp
const res = await api(`/v1/changelog?since=${since}&limit=200`);
for (const ch of res.data) {
  if (ch.institution_id) {
    const fresh = await api(`/v1/institutions/${ch.institution_id}`);
    await store.upsert(fresh.data);                          // id is stable across renames
  }
  // kind === "sentinel_change_approved" may reference new institutions —
  // resolve via /v1/search on change.institution_name
}
await store.set("akadaiq_last_sync", new Date().toISOString());

Enterprise-tier accounts can subscribe to webhooks for push delivery of the same events (institution updated, blacklist addition, verification-status change) — contact partnerships to configure endpoints and signing secrets.

Guide — best practices

Resolve names once, store ids forever. Human-entered institution names are the largest source of duplicate and mismatched records in Nigerian education data. Run /v1/search at intake, let the user confirm, and persist the canonical id.

Pass names raw to verification. Don't pre-normalize before calling /v1/verify/institution — the matcher is tuned for real Nigerian usage (acronyms, "Fed Poly X", name+town) and pre-cleaning can strip its signal.

Log the reference, and store the provenance you acted on. Your audit posture is strongest when your records show not just the verdict but the evidence state at decision time.

Treat NOT_FOUND as triage, not rejection — offer the closest_matches, then route to manual review. Treat ILLEGAL as a hard stop pending human confirmation against the current NUC publication, as the response itself instructs.

Cache reads, never cache verifications. Registry lookups are cache-friendly (respect the changelog); verification calls should always be live — that's the point of them, and each one creates the audit entry you'll want later.

Handle 429 with backoff and monitor your quota tier. Retry idempotent GETs with exponential backoff (base 2s, max 3 retries); don't auto-retry POSTs without idempotency handling on your side.

Keys in browsers: the embeddable widget pattern is supported, but a browser-visible key is public. Use a dedicated low-tier key for widgets, keep verification-tier keys server-side only.

Compliance & audit notes

Every verification call is logged server-side with its AKD- reference, timestamp, verdict, and calling key — enterprise accounts can request periodic verification-ledger exports for regulator or oversight reporting. Registry changes are individually changelog-audited, including who approved each Sentinel extraction. AkadaIQ is Nigerian-founded and Nigerian-operated; dedicated deployments are available for data-sovereignty requirements. AkadaIQ provides evidence, not legal conclusions: verdicts summarize regulator publications and registry state, and integrators remain responsible for their own compliance decisions.

Versioning & support

/v1 is stable: fields may be added to responses without notice (build tolerant parsers), but existing fields, verdict strings, and error shapes will not change within v1. Breaking changes ship as /v2 with a minimum 6-month overlap. Deprecations are announced in the changelog and by email to key holders.

Support: developers@akadaiq.com · partnerships and enterprise: partnerships@akadaiq.com · live status: /v1/health · registry coverage: /v1/stats.

AkadaIQ — Nigeria's Education Trust Infrastructure. Regulator sources: NUC · NBTE · NCCE · JAMB. © 2026 AkadaIQ, a DoktorConnect company.