Skip to main content

Integration guide: building a mock-exam flow

This walks through a complete, production-shaped integration: let a student pick an exam, sit a timed past paper, and see a scored result — backed by verified MirrorMingo content.

We use the TypeScript SDK; the shape is identical in every language.

Architecture

Browser / app ──► Your backend ──► MirrorMingo Exam API
(holds the API key)

Keep the API key on your server. The browser talks to your backend; your backend talks to MirrorMingo. This keeps the key secret and lets you add your own auth, caching and analytics.

1. Let the student choose an exam

// GET /api/exams (your backend)
app.get("/api/exams", async (req, res) => {
const exams = await mm.exams.list({ country: req.query.country as string });
res.json(exams);
});

Exam metadata (names, sections, scoring) changes rarely — cache it for a day.

2. List verified past papers

app.get("/api/exams/:examKey/papers", async (req, res) => {
const catalog = await mm.mockExams.listPapers(req.params.examKey);
res.json(catalog);
});

Each paper has a stable paper_id grouped under a year. Render a year picker.

3. Start a timed attempt

app.post("/api/exams/:examKey/start", async (req, res) => {
const attempt = await mm.mockExams.open(req.params.examKey, {
paperId: req.body.paperId,
questionLimit: 20,
});
// Persist attempt.attempt_id against the signed-in student so a refresh
// resumes the same attempt. Start your countdown from the exam's duration.
res.json(attempt);
});

For long papers, page with mm.mockExams.questions(examKey, { paperId, questionOffset }). has_visual: true marks questions that reference a figure — render a note for those.

4. Submit and score

app.post("/api/exams/:examKey/submit", async (req, res) => {
const result = await mm.mockExams.submit(req.params.examKey, {
attemptId: req.body.attemptId,
answers: req.body.answers, // { "1": "C", "2": "A", ... }
status: req.body.timedOut ? "expired" : "submitted",
});
res.json(result.feedback);
});

feedback carries the score and per-question correctness/explanations.

5. (Optional) React to scoring with webhooks

Instead of blocking the UI on scoring, subscribe to mock_attempt.scored and update the student's dashboard when the event arrives — see Webhooks.

Production checklist

  • API key stored in a secret manager, never shipped to the client
  • Exam/paper metadata cached (≥1 day)
  • attempt_id persisted per student so attempts survive a refresh
  • Server-side countdown; submit with status: "expired" on timeout
  • Handle 429 with backoff (the SDK does this automatically)
  • Sandbox used in CI; production key only in prod