High-Throughput Assessment Microservice Engine

ParaLearn CBT Developer API

Programmatically provision exams, manage question banks with LaTeX/Markdown, launch high-concurrency candidate test sessions, track real-time malpractice telemetry, and receive auto-graded results via HMAC-signed webhooks.

Base API URL:https://cbt-api.pln.ng
Protocol:HTTPS / TLS 1.3
Response Format:JSON (RFC 8259)

1. Authentication

Every request from an external application must include your secret API key in the authorization header. You receive this key upon creating or signing in to an exam hall workspace.

# Pass in standard Authorization header:
Authorization: Bearer pln_live_sk_sample_••••••••••••••••

# Or using the custom header:
x-api-key: pln_live_sk_sample_••••••••••••••••

2. Workspaces & Developer Keys

Create and manage autonomous workspaces for your academy, school, or tutorial centre. Each standalone workspace receives 30 free candidate testing credits automatically upon creation.

POST/workspaces/standalone
Register Partner Exam Hall

Request Body:

{
  "name": "Standard Assessment Centre",
  "ownerName": "Centre Administrator",
  "email": "examiner@example.com",
  "webhookUrl": "https://api.example.com/webhooks/cbt-results"
}

Response (201 Created):

{
  "id": "ws_sample_0001",
  "name": "Standard Assessment Centre",
  "type": "STANDALONE_HALL",
  "credits": 30,
  "apiKey": "pln_live_sk_sample_••••••••••••••••",
  "webhookSecret": "pln_whsec_sample_••••••••••••••••"
}
POST/workspaces/login
Examiner Sign In & Recovery

Authenticates an examiner using their registered email. Restores their API keys, credit balance, and exam counts. If the account is new, it automatically provisions a workspace with 30 free test credits.

Request Body:

{
  "email": "examiner@example.com",
  "password": "your_secure_password"
}

Response (200 OK):

{
  "id": "ws_sample_0001",
  "name": "Standard Assessment Centre",
  "ownerName": "Centre Administrator",
  "ownerEmail": "examiner@example.com",
  "credits": 30,
  "apiKey": "pln_live_sk_sample_••••••••••••••••",
  "_count": {
    "exams": 4,
    "questions": 150
  }
}
POST/workspaces/institution
ParaLearn School SIS SSO

Request Body:

{
  "schoolId": "sch_sample_99182",
  "schoolName": "Exemplar Academy",
  "email": "admin@school.example.edu.ng"
}

3. Exams Management

Provision exams with custom delivery policies including room code generation, anti-cheat limits, question shuffling, and optional date & time scheduling windows (startsAt, endsAt).

POST/exams
Create & Schedule Exam

Request Body:

{
  "workspaceId": "ws_sample_0001",
  "title": "UTME 2026 Mock — Mathematics",
  "durationMins": 60,
  "accessCode": "MOCK-MTH-26",
  "startsAt": "2026-10-02T09:00:00.000Z",
  "endsAt": "2026-10-02T17:00:00.000Z",
  "maxTabViolations": 3,
  "shuffleQuestions": true,
  "shuffleChoices": true,
  "showResultAfter": true
}

Response (201 Created):

{
  "id": "exam_clx9921",
  "workspaceId": "ws_sample_0001",
  "title": "UTME 2026 Mock — Mathematics",
  "accessCode": "MOCK-MTH-26",
  "durationMins": 60,
  "startsAt": "2026-10-02T09:00:00.000Z",
  "endsAt": "2026-10-02T17:00:00.000Z",
  "isPublished": true,
  "createdAt": "2026-09-29T18:00:00.000Z"
}
GET/exams?workspaceId={id}
List All Exam Rooms

Response (200 OK):

[
  {
    "id": "exam_clx9921",
    "title": "UTME 2026 Mock — Mathematics",
    "accessCode": "MOCK-MTH-26",
    "durationMins": 60,
    "startsAt": "2026-10-02T09:00:00.000Z",
    "endsAt": "2026-10-02T17:00:00.000Z",
    "_count": {
      "questions": 40,
      "attempts": 14
    }
  }
]

4. Question Studio & LaTeX Ingestion

Questions support full Markdown and LaTeX mathematical notation (e.g. $E = mc^2$). You can inject questions in bulk or upload an .xlsx spreadsheet via POST /questions/import-excel.

POST/questions/bulk
Bulk Ingest Questions
{
  "workspaceId": "ws_sample_0001",
  "examId": "exam_sample_101",
  "questions": [
    {
      "prompt": "Calculate the kinetic energy: $E_k = \\frac{1}{2}mv^2$ for $m=2\\text{kg}, v=3\\text{m/s}$",
      "type": "MCQ",
      "marks": 1.0,
      "options": [
        { "id": "opt_a", "keyLabel": "A", "text": "6 Joules", "isCorrect": false },
        { "id": "opt_b", "keyLabel": "B", "text": "9 Joules", "isCorrect": true }
      ],
      "explanation": "$E_k = 0.5 \\times 2 \\times 3^2 = 9\\text{ J}$."
    }
  ]
}
POST/api/cbt/ai/generate-questions
ParaLearn Multimodal AI Ingestion

Extracts context and concepts directly from uploaded lecture documents (PDF, Word, TXT), presentation slide decks (PPTX), audio recordings (MP3, WAV), or lecture videos (MP4), calibrating question difficulty according to Bloom's Taxonomy.

Multipart Form Fields:

  • file (Binary, optional): PDF document, PPTX slides, MP3/WAV audio, or MP4 video (up to 40MB).
  • notes (String, optional): Plaintext or markdown lecture notes/transcripts.
  • difficulty (String): simple (recall), intermediate (application), hard (synthesis), or balanced (progressive mix).
  • count (Integer): Target number of questions to author (default: 10).
  • subject (String): Topic or curriculum context.

Response (200 OK):

{
  "success": true,
  "engine": "ParaLearn AI Engine",
  "difficulty": "balanced",
  "totalGenerated": 10,
  "questions": [
    {
      "id": "pln_ai_q_17907502",
      "prompt": "According to Newton's Second Law, if the net force acting on an object is doubled while its mass remains constant, the acceleration will:",
      "type": "MCQ",
      "marks": 1.0,
      "difficulty": "simple",
      "citation": "Slide 4 (F = ma)",
      "explanation": "Acceleration is directly proportional to net force for constant mass.",
      "options": [
        { "id": "opt_0_0", "text": "Double", "isCorrect": true },
        { "id": "opt_0_1", "text": "Halve", "isCorrect": false },
        { "id": "opt_0_2", "text": "Remain unchanged", "isCorrect": false },
        { "id": "opt_0_3", "text": "Quadruple", "isCorrect": false }
      ]
    }
  ]
}
SCHEMAHybrid Assessment Taxonomy (v1.3.0)
MCQ • Short Essay • Long Essay

ParaLearn CBT supports mixing objective MCQs with Short Essays (20–100 words) and Extended Compositions (150–800 words), each backed by customizable weighted criteria, model benchmark solutions, and institutional rubrics (WAEC, Cambridge, STEM).

{
  "type": "LONG_ESSAY", // "MCQ" | "SHORT_ESSAY" | "LONG_ESSAY" | "TRUE_FALSE"
  "prompt": "Critically analyze the fiscal impact of subsidy removal...",
  "marks": 15.0,
  "section": "Section C: Extended Essay",
  "minWords": 150,
  "maxWords": 800,
  "modelAnswer": "Comprehensive expected arguments, thesis points, and proofs...",
  "rubric": {
    "name": "Standard Essay Evaluation Scheme",
    "totalMarks": 15,
    "criteria": [
      { "id": "c1", "title": "Thesis & Content Depth", "maxMarks": 5, "description": "Grasp of key concepts and empirical evidence." },
      { "id": "c2", "title": "Structure & Logical Flow", "maxMarks": 5, "description": "Coherence, transitions, and paragraphing." },
      { "id": "c3", "title": "Expression & Diction", "maxMarks": 5, "description": "Clarity of vocabulary, spelling, and grammar." }
    ]
  }
}
POST/api/cbt/ai/grade-essay
ParaLearn AI Essay Grading Engine

Evaluates a candidate's written response against the question prompt, teacher model answer, and rubric criteria, returning recommended numeric criteria scores, criterion observations, and overall constructive feedback that examiners can review, tweak, and approve.

Request Body:

{
  "questionPrompt": "Distinguish between speed and velocity with an example.",
  "studentResponse": "Speed is a scalar quantity while velocity is a vector quantity that has direction...",
  "modelAnswer": "Speed is distance/time; velocity is displacement/time with direction.",
  "rubricCriteria": [
    { "id": "c1", "title": "Definition & Scalar/Vector Distinction", "maxMarks": 3 },
    { "id": "c2", "title": "Practical Application Example", "maxMarks": 2 }
  ],
  "maxMarks": 5.0
}

Response (200 OK):

{
  "success": true,
  "engine": "ParaLearn AI Grading Engine",
  "evaluation": {
    "criteriaScores": [
      { "criterionId": "c1", "score": 3.0, "maxMarks": 3, "feedback": "Accurately noted scalar vs vector distinction." },
      { "criterionId": "c2", "score": 1.5, "maxMarks": 2, "feedback": "Example was valid but lacked directional unit specification." }
    ],
    "totalScore": 4.5,
    "maxScore": 5.0,
    "overallComment": "Strong grasp of kinematics fundamentals with clear distinction of scalar and vector quantities.",
    "strengths": ["Accurate scalar/vector definitions", "Good conceptual clarity"],
    "areasForImprovement": ["Include explicit vector directions (e.g. 50 km/h North) in real-world examples"]
  }
}

5. Candidate Runner & Session Ingestion

When a student starts an exam via POST /attempts/start, all correct answer keys are stripped from the response payload for strict security. Live answers are buffered in high-throughput in-memory caching (<5ms latency) to prevent database contention during concurrent mock tests.

POST/attempts/start
Initiate Candidate Session

Request Body:

{
  "accessCode": "MOCK-SCI-26",
  "candidatePin": "849201",
  "candidateName": "Sample Candidate",
  "studentId": "std_demo_101"
}

Response (200 OK — Correct answer keys omitted):

{
  "isResumed": false,
  "attemptId": "att_sample_202",
  "examId": "exam_sample_101",
  "examTitle": "UTME 2026 Mock — General Science",
  "candidateName": "Sample Candidate",
  "remainingSeconds": 3600,
  "violations": 0,
  "maxTabViolations": 3,
  "questions": [
    {
      "id": "q_01",
      "prompt": "Calculate kinetic energy: $E_k = \\frac{1}{2}mv^2$...",
      "options": [
        { "id": "opt_a", "keyLabel": "A", "text": "6 Joules" },
        { "id": "opt_b", "keyLabel": "B", "text": "9 Joules" }
      ]
    }
  ]
}

6. Proctoring & Anti-Cheat Telemetry

The client runner monitors browser window blur, tab switches, and fullscreen exits. Every event is dispatched to POST /attempts/:id/telemetry. If violations exceed maxTabViolations, the candidate is automatically disqualified and the session is locked.

POST/attempts/:id/telemetry
Record Breach Event
{
  "type": "TAB_SWITCH",
  "meta": { "action": "window_blur" }
}

7. Deterministic Auto-Grading & WAEC Scoring

Upon calling POST /attempts/:id/submit, the server deterministically auto-grades MCQ/TF questions, calculates the percentage, and computes the standard Nigerian WAEC/NECO grade:

≥ 75%: A1
≥ 70%: B2
≥ 65%: B3
≥ 60%: C4
< 40%: F9
POST/attempts/:id/submit
Finalize & Auto-Grade

Response (200 OK):

{
  "attemptId": "att_sample_202",
  "score": 36.0,
  "maxScore": 40.0,
  "percentage": 90.0,
  "grade": "A1",
  "status": "COMPLETED",
  "completedAt": "2026-09-29T17:40:00.000Z"
}

8. Webhook Verification

When an attempt is finalized, an exam.attempt.completed event is dispatched to your webhook URL with an x-cbt-signature: sha256=<hash> header.

// Node.js / Express Signature Verification:

const crypto = require("crypto");

function verifyWebhook(rawBody, signature, secret) {
  const hash = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(`sha256=${hash}`));
}

9. Errors & HTTP Status Codes

ParaLearn CBT returns conventional HTTP status codes. Detailed error summaries are provided in standard RFC 7807 problem details format.

CodeStatusDescription
200 / 201SuccessRequest processed successfully.
400Bad RequestValidation failure or missing required fields in payload.
401UnauthorizedAPI Key is missing or invalid. Check your Authorization: Bearer header.
402Payment RequiredCandidate testing credit exhausted. Top up your workspace credits.
403ForbiddenAttempt disqualified due to proctoring violations or session locked.
404Not FoundRequested workspace, exam, question, or attempt was not found.
429Too Many RequestsRate limit exceeded (> 120 req/min for general API, > 600 req/min for live response buffering).

10. API Versioning & Release Changelog

ParaLearn CBT uses semantic versioning (MAJOR.MINOR.PATCH). Breaking schema modifications increment the major version, while backwards-compatible endpoints and parameter additions increment minor versions.

v1.2.0Multimodal ParaLearn AI Question Generation
Current Stable
  • Added POST /api/cbt/ai/generate-questions for multimodal ingestion of documents (PDF, Word, TXT), slides (PPTX), audio (MP3, WAV), and video (MP4).
  • Integrated Bloom's Taxonomy difficulty tuning: simple (recall), intermediate (application), hard (synthesis), or balanced mix.
  • Automated psychometric distractor formulation with grounded citations (page/slide numbers or video timestamps).
  • Interactive ParaLearn AI Question Studio modal with preview, inline editing, and 1-click palette import.
v1.1.0Multi-Exam Scheduling & Window Controls
September 2026
  • Added startsAt and endsAt ISO-8601 date/time window parameters on POST /exams.
  • Added GET /exams?workspaceId={id} endpoint for listing all examination rooms in an exam hall.
  • Enabled independent examiners to manage and launch multiple distinct examinations concurrently.
  • Integrated candidate roster management with 1-click WhatsApp and magic link PIN dissemination.
v1.0.0Initial Public Microservice Release
September 2026
  • Core autonomous CBT workspace and standalone self-serve provisioning (30 free test credits).
  • Low-latency candidate session runner (Redis buffered response ingestion <5ms).
  • Real-time anti-cheat telemetry and deterministic WAEC/NECO auto-grading.
  • HMAC-SHA256 signed webhook dispatches (exam.attempt.completed).