Documentation

SdashAPI Reference

A REST API for Nigerian past exam questions (UTME, WASSCE, NECO, Post-UTME) with answers and solutions.

Introduction

SdashAPI returns JSON. Base URL:

https://sdashapi.com/api/

All responses have a top-level status field (HTTP status code) and either a data field (success) or a message field (error).

Authentication & Making Requests

To securely access the API, you must include your unique AccessToken in the HTTP headers of every request. You can locate your Access Token on your dashboard.

Here are examples of how to make your first API call using different programming languages:

cURL (Terminal)
curl "https://sdashapi.com/api/v1/q?subject=biology" \
  -H "AccessToken: YOUR_ACCESS_TOKEN"
JavaScript (Fetch)
fetch("https://sdashapi.com/api/v1/q?subject=biology", {
  headers: {
    "AccessToken": "YOUR_ACCESS_TOKEN"
  }
})
.then(response => response.json())
.then(data => console.log(data));
PHP (cURL)
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://sdashapi.com/api/v1/q?subject=biology");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "AccessToken: YOUR_ACCESS_TOKEN"
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
Python (Requests)
import requests

url = "https://sdashapi.com/api/v1/q?subject=biology"
headers = {"AccessToken": "YOUR_ACCESS_TOKEN"}

response = requests.get(url, headers=headers)
print(response.json())

Note: You can also pass the token as a URL query parameter (?token=YOUR_TOKEN) for quick browser testing, but using the HTTP header is strongly recommended for security in production applications.

Don't have a token yet? Create a free account to generate one.

JavaScript / TypeScript SDK

Official Node.js and TypeScript SDK for SdashAPI. Give your developers instant access to thousands of past exam questions.

Installation

npm install @sdashapis/sdk
# or yarn add @sdashapis/sdk
# or pnpm add @sdashapis/sdk

Quick Start

import { SdashAPI } from '@sdashapis/sdk';

// 1. Initialize the client
const api = new SdashAPI({
  apiKey: 'YOUR_ACCESS_TOKEN', // Get your token from sdashapi.com/dashboard
});

async function main() {
  try {
    // 2. Fetch a random chemistry UTME question from 2022
    const question = await api.getQuestions({
      subject: 'chemistry',
      type: 'utme',
      year: 2022
    });
    console.log(question);
    /* Output:
    {
      id: 4821,
      question: "Which of the following is the chemical formula for table salt?",
      option: { a: "NaCl", b: "KCl", c: "CaCO3", d: "NaOH" },
      answer: "a",
      ...
    } */

    // 3. Fetch 10 random questions
    const questionsList = await api.getQuestions({ limit: 10 });
    console.log(`Fetched ${Array.isArray(questionsList) ? questionsList.length : 1} questions`);
  } catch (error) {
    console.error("Failed to fetch questions:", error.message);
  }
}

main();

Endpoints Supported

  • getQuestions(params): Fetch past questions with filters.
  • getSubjects(): List available subjects (Biology, Chemistry, etc.).
  • getExams(): List supported exams (UTME, WASSCE, NECO, etc.).
  • getYears(): List available years.
  • reportQuestion(params): Report issues with questions (typos, wrong answers).

Python SDK

Official Python SDK for SdashAPI - Access Nigerian past exam questions (UTME, WASSCE, NECO, Post-UTME).

Installation

In a virtualenv (see these instructions if you need to create one):

pip3 install sdashapis-sdk

Dependencies & Links

Fetch questions

GET /api/v1/q

Returns one or more past-exam questions from our bank (2001–2026). By default returns one random question. Use query parameters to filter by subject, exam type and year.

Query parameters

ParamTypeDescription
subjectstringoptionalSubject slug e.g. chemistry, mathematics. Get slugs from /v1/subjects.
typestringoptionalExam type slug: utme, wassce, neco, post-utme, university.
yearstringoptional4-digit year e.g. 2020. Coverage: 2001–2026. Get valid years from /v1/years.
universitystringoptionalFilter questions by university slug/name e.g. unilag. Primarily used for Post-UTME.
idintegeroptionalFetch a specific question by its ID.
limitintegeroptionalNumber of questions to return (maximum 50 per request). Default: 1. When limit=1 the response data is an object; limit>1 returns an array.

Response object schema

FieldTypeDescription
idintegerUnique question ID.
questionstringThe question text.
sectionstring | nullOptional shared passage or instruction block for a group of questions.
optionobjectNested object with keys a, b, c, d (and optionally e) containing the option texts.
answerstringThe correct option key e.g. "b".
solutionstring | nullWorked solution or explanation.
imagestring | nullURL to an image associated with the question, if any.
examtypestringExam name e.g. "UTME", "WASSCE", "NECO", "Post-UTME", "University".
examyearstring4-digit year as a string e.g. "2023".
universitystring | nullThe university name, if applicable.

Example 1 — UTME (Chemistry)

Request
GET /api/v1/q?subject=chemistry&type=utme&year=2022
AccessToken: YOUR_ACCESS_TOKEN
Response
{
  "status": 200,
  "data": {
    "id": 4821,
    "question": "Which of the following is the chemical formula for table salt?",
    "section": null,
    "option": {
      "a": "NaCl",
      "b": "KCl",
      "c": "CaCO3",
      "d": "NaOH"
    },
    "answer": "a",
    "solution": "NaCl is sodium chloride...",
    "image": null,
    "examtype": "UTME",
    "examyear": "2022",
    "university": null
  }
}

Example 2 — WASSCE (Mathematics)

Specify type=wassce to retrieve WASSCE past questions.

Request
GET /api/v1/q?subject=mathematics&type=wassce&limit=1
AccessToken: YOUR_ACCESS_TOKEN
Response
{
  "status": 200,
  "data": {
    "id": 5102,
    "question": "Solve for x: 2x + 5 = 15",
    "section": null,
    "option": {
      "a": "2",
      "b": "5",
      "c": "10",
      "d": "20"
    },
    "answer": "b",
    "solution": "Subtract 5 from both sides: 2x = 10. Divide by 2: x = 5.",
    "image": null,
    "examtype": "WASSCE",
    "examyear": "2021",
    "university": null
  }
}

Example 3 — Post-UTME (English Language)

Specify type=post-utme for university screening questions.

Request
GET /api/v1/q?subject=english&type=post-utme&limit=1
AccessToken: YOUR_ACCESS_TOKEN
Response
{
  "status": 200,
  "data": {
    "id": 8931,
    "question": "Choose the word nearest in meaning to the italicized word: His behavior was rather erratic.",
    "section": null,
    "option": {
      "a": "predictable",
      "b": "inconsistent",
      "c": "polite",
      "d": "dangerous"
    },
    "answer": "b",
    "solution": "Erratic means not even or regular in pattern or movement; unpredictable or inconsistent.",
    "image": null,
    "examtype": "Post-UTME",
    "examyear": "2019",
    "university": "UNILAG"
  }
}

Example — 10 random questions (mixed)

GET /api/v1/q?limit=10
AccessToken: sdash_xxxxxxxxxxxx

V2 API: Metadata & Taxonomy

Use /api/v2/q to receive additional metadata (topics, difficulty, tags, passage text).

{
  "id": 8931,
  "question": "...",
  "metadata": {
    "topic": "Organic Chemistry",
    "subtopic": "Alkanes",
    "difficulty": "medium",
    "type": "MCQ",
    "skill": "Recall",
    "tags": ["hydrocarbons", "covalent"],
    "passage": null
  }
}

V3 API: Explanations

Use /api/v3/q to receive everything in V2 plus a detailed AI-generated or expert explanation block.

{
  "id": 8931,
  "question": "...",
  "metadata": { ... },
  "explanation": {
    "summary": "Quick summary of the answer.",
    "detailed": "Detailed step-by-step reasoning...",
    "steps": ["Step 1...", "Step 2..."],
    "why_correct": "Option B is correct because...",
    "why_others_wrong": {"a": "Incorrect because...", "c": "..."}
  }
}

V4 API: Intelligence (Similar Questions)

Use /api/v4/q for the main questions. In addition, V4 introduces /api/v4/similar?id=123&limit=5 to fetch questions related to a specific question.

GET /api/v4/similar?id=123
{
  "status": 200,
  "data": [
    {
      "id": 8932,
      "relationship_type": "similar_concept",
      "score": 0.95,
      "question": "...",
      "answer": "c",
      "image": null,
      "examtype": "UTME",
      "examyear": "2022",
      "university": null
    }
  ]
}

List Novels (V4)

GET /api/v4/novels

Returns a list of all literature novels with their basic information and cover image URLs. Supports pagination via page and limit parameters.

{
  "status": 200,
  "data": [
    {
      "id": 1,
      "title": "Things Fall Apart",
      "author": "Chinua Achebe",
      "description": "A classic African novel...",
      "cover_image": "https://...",
      "has_practice_questions": true
    }
  ],
  "pagination": {
    "total": 12,
    "per_page": 10,
    "current_page": 1,
    "total_pages": 2,
    "has_more": true
  }
}

Novel Details (V4)

GET /api/v4/novel?id=1

Returns the deep JSON structure for a specific novel, including themes, characters, and chapter summaries.

{
  "status": 200,
  "data": {
    "id": 1,
    "title": "Things Fall Apart",
    "themes": ["Tradition vs. Change", "Masculinity"],
    "characters": ["Okonkwo", "Nwoye"],
    "chapter_summaries": [
      {
        "title": "Chapter 1",
        "content": "Okonkwo is introduced as a strong wrestler..."
      }
    ]
  }
}

Novel Practice Questions (V4)

GET /api/v4/novel/q?novel_id=1

Fetch dedicated practice questions for a specific novel. Supports pagination.

Query parameters

ParamTypeDescription
novel_idintegerrequiredThe ID of the novel.
pageintegeroptionalThe page number to fetch. Default: 1.
limitintegeroptionalNumber of questions per page (maximum 50). Default: 20.
{
  "status": 200,
  "data": [
    {
      "id": 9050,
      "question": "What is Okonkwo's greatest fear?",
      "option": {
        "a": "Failure and weakness",
        "b": "The white man",
        "c": "The gods",
        "d": "His wives"
      },
      "answer": "a"
    }
  ],
  "pagination": {
    "total": 50,
    "per_page": 20,
    "current_page": 1,
    "total_pages": 3,
    "has_more": true
  }
}

List subjects

GET /api/v1/subjects

Returns all available subjects and their slugs (use the slug as the subject filter).

Available Subjects

You can also use any of the following slugs directly in your API requests:

Accounting
slug: accounting
Agriculture
slug: agriculture
Arabic Studies
slug: arabic
Biology
slug: biology
Chemistry
slug: chemistry
Civic Education
slug: civiledu
Commerce
slug: commerce
Computer Studies
slug: computer
CRK
slug: crk
Current Affairs
slug: currentaffairs
Economics
slug: economics
English Language
slug: english
English Literature
slug: englishlit
Fine Art
slug: fineart
Geography
slug: geography
Government
slug: government
Hausa
slug: hausa
History
slug: history
Home Economics
slug: homeeconomics
Igbo
slug: igbo
Insurance
slug: insurance
IRK
slug: irk
Mathematics
slug: mathematics
Music
slug: music
Physics
slug: physics
Yoruba
slug: yoruba
{
  "status": 200,
  "data": [
    { "id": 1, "name": "Biology", "slug": "biology" },
    { "id": 2, "name": "Chemistry", "slug": "chemistry" },
    ...
  ]
}

List exam types

GET /api/v1/exams

Returns all exam types and their slugs (use as the type filter).

List years

GET /api/v1/years

Returns a list of available years as integers, newest first.

Report a question

POST /api/v1/report

Lets your users flag a question that has a wrong answer, typo, or other issue. Send JSON body:

FieldTypeDescription
question_idintegerrequiredThe id from the question object.
report_typestringoptionalOne of: wrong_answer, typo, unclear, other. Default: wrong_answer.
messagestringoptionalExtra detail from the user.
Request
POST /api/v1/report
AccessToken: sdash_xxxxxxxxxxxx
Content-Type: application/json

{
  "question_id": 4821,
  "report_type": "wrong_answer",
  "message": "Option B should be the correct answer."
}
Response
{
  "status": 200,
  "message": "Report submitted. Thank you!"
}

Error codes

StatusMeaning
200Request succeeded.
400Bad request — check your parameters.
401Missing or invalid AccessToken.
403Account suspended.
404No questions matched your filters, or unknown endpoint.
405Wrong HTTP method.
429Monthly quota exceeded — upgrade your plan.

Rate limits & quotas

API calls are unlimited for all our paid plans as detailed on our Pricing page.

Need a custom enterprise solution? Contact us.

Avatar

How can we help?

We reply immediately

Hello! 👋 How can we help you today?