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.
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:
| Consumer | Typical usage |
|---|---|
| Lenders & fintech (student loans, KYC) | POST /v1/verify/institution as a disbursement or onboarding gate; GET /v1/changelog for continuous monitoring |
| Edtech & admission platforms | GET /v1/search autocomplete, GET /v1/institutions filtering, POST /v1/admitiq/probability |
| HR & background-check services | POST /v1/verify/institution and POST /v1/verify/program for credential screening |
| AI agents & assistants | The MCP server, or POST /v1/ask for grounded natural-language answers |
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
| HTTP | Meaning | Typical cause & fix |
|---|---|---|
400 | Bad request | Missing/invalid body field or query parameter. The message names the field. |
401 | Unauthenticated | No key, or key not found. Check the x-api-key header. |
403 | Forbidden | Key deactivated, or endpoint requires a higher tier. |
404 | Not found | Unknown endpoint or institution id. Use /v1/search to resolve ids. |
405 | Method not allowed | GET sent to a POST endpoint (verification, ask, AdmitIQ are actions, not pages). |
429 | Rate limited | Daily quota reached for the key's tier. Resets at 00:00 UTC. Upgrade or retry tomorrow. |
500 | Server error | Retry with exponential backoff; if persistent, contact support with the timestamp. |
Tiers & rate limits
| Tier | Daily requests | Scope |
|---|---|---|
free | 100 | Registry, search, verification, ask, AdmitIQ — evaluation use |
growth | 10,000 | Full API for production edtech / platform use |
verification | 50,000 | High-volume EduKYC workloads; per-check billing with audit reporting |
enterprise | Custom | SLA, 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.
| Field | Type | Description |
|---|---|---|
id | string | Canonical slug. Stable. Use this as your foreign key. |
name | string | Current official name. |
acronym | string | null | Common acronym (UNILAG, FUTA, LASU) where one exists. |
type | enum | university · polytechnic · college_of_education |
ownership | enum | federal · state · private |
state, city | string | null | Location (Nigerian state; host town/city). |
regulator | enum | NUC · NBTE · NCCE |
status | string | active in the normal case; proposed for announced-but-unconfirmed institutions. |
year_established, website, jamb_code, logo_url | various | null | Enrichment fields, populated progressively by curation. |
officers, campuses | array | Key officers and campus list, populated progressively. |
courses | array | Programme 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. |
provenance | object | See Provenance. Present on every record; ships even under field selection. |
needs_review, review_note | boolean, string | null | Set 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 }
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:
| Verdict | Meaning | Suggested action |
|---|---|---|
RECOGNISED | Confident registry match; institution active under its regulator. | Proceed. Record the reference and the returned provenance. |
RECOGNISED_WITH_FLAGS | Matched, but record status is not plain active (e.g. proposed). | Manual review before high-stakes actions. |
ILLEGAL | Name matches the NUC illegal-institutions blacklist. | Stop. Do not disburse/accept. Confirm against the current NUC publication as the response instructs. |
NOT_FOUND | No 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_RECORD | Programme found; accreditation status returned (incl. at graduation year where history exists). | Proceed per your accreditation policy. |
PROGRAM_NOT_ON_RECORD | Institution 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. |
List and filter the registry. Returns paginated institution records sorted alphabetically, or by relevance when search is used.
| Query param | Type | Description |
|---|---|---|
type | enum | university · polytechnic · college_of_education |
ownership | enum | federal · state · private |
state | string | Nigerian state, case-insensitive (e.g. Lagos, Akwa Ibom) |
regulator | enum | NUC · NBTE · NCCE |
status | string | e.g. active, proposed |
verified | boolean | true restricts to curator-verified records only |
search | string | Fuzzy match on name/acronym/town — handles Nigerian shorthand (Fed Poly Nekede, LASU Ojo, Ibadan Poly) |
fields | csv | Field selection, e.g. name,state,ownership. id and provenance always included. |
page / per_page | int | Default 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 } }
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"
Programmes on record for one institution. Filters: name (substring), accreditation (exact status). Returns { institution, count, courses }.
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.
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 param | Description |
|---|---|
q (required) | Partial name, acronym, or name+town. The matcher expands Nigerian shorthand: poly→polytechnic, uni/varsity→university, fed→federal. |
limit | Max 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 }
] }
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.
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.
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 param | Description |
|---|---|
since | ISO-8601 timestamp; returns only changes after it (e.g. 2026-07-01T00:00:00Z) |
limit | Max 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": "…" } }
] }
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 field | Type | Description |
|---|---|---|
name (required) | string | Institution 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.
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 field | Type | Description |
|---|---|---|
institution (required) | string | Institution name (fuzzy-resolved) |
program (required) | string | Programme name, e.g. Pharmacy |
graduation_year | int | Optional. 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.
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 field | Description |
|---|---|
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", … } ] } }
/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.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 field | Type | Description |
|---|---|---|
utme_score (required) | int 0–400 | Candidate UTME score |
course (required) | string | Programme of interest |
state, ownership, type | string | Optional 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.
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.
| Tool | Arguments | Returns |
|---|---|---|
search_institutions | query?, state?, type?, ownership? | Up to 15 matches with verification status |
get_institution | id | Full record incl. provenance |
verify_institution | name | RECOGNISED / ILLEGAL / NOT_FOUND with guidance |
registry_stats | — | Aggregate 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.