---
title: "Api Learning Submit Quiz"
method: POST
path: "/api/learning/submit-quiz"
tags: ["Education"]
---

# Api Learning Submit Quiz

`POST /api/learning/submit-quiz`

## Request

- Base URL: `https://www.oxfordledge.com` (the document declares no server; this is the origin it was published from)
- URL: `https://www.oxfordledge.com/api/learning/submit-quiz`
- Auth: none declared

Server-graded module quiz with attempt chain and rate limiting.

## Response `200`

Successful Response

- QuizGradeResponse: Response from POST /api/learning/submit-quiz. The endpoint is the canonical server-side grader for both quiz and apply tasks. It returns `correct`, the running attempt count, the derived mastery score, and (only after the attempt chain terminates) the correct option index + explanation. Several fields are branch-conditional and so declared Optional: - ``correct_option`` / ``explanation``: only disclosed when ``chain_terminated AND user_id`` (CISO P0 — never disclosed to anonymous callers, see plan §8 risk row). - ``replayed``: True on the early-return paths (unauth-cap, prior-terminated-fail) where the server returns the cached terminal verdict instead of grading a new attempt. - ``requires_signup``: True only on the unauth-cap path. Frontend flips this to a sign-up CTA. - ``remediation``: present when the Adaptive Mastery System decides to offer a primer (sub-70 score, eligible source module). Shape is opaque-to-client; rendered by the frontend via ``learning-paths.ts`` § _LP_PRIMER_SECTION_TYPES. `_Base` carries `extra="allow"` so future additive fields don't break existing SDK consumers.
  - `correct` boolean, required: True iff the submitted option matched the answer key.
  - `attempts` integer, required: Running count of attempts on this module (1 or 2 — the chain terminates at 2 attempts regardless of correctness).
  - `mastery_score` integer, nullable: Mastery score for the attempt: 100 (correct, 1st attempt, no hint), 85 (correct, 1st attempt, hint used), 70 (correct, 2nd attempt), 40 (incorrect, chain terminated). None when the chain hasn't terminated yet.
  - `passed` boolean, required: True iff `correct` is True. Distinct from `mastery_passed` in PG which only flips on score >= 70.
  - `can_retry` boolean, required: True iff the user may submit a second attempt for this module (i.e., NOT correct AND attempts < 2).
  - `correct_option` integer, nullable: 0-indexed correct-answer index. ONLY disclosed after chain_terminated AND for authed users. Anonymous callers always get None — CISO §8 mandate (plan §8 risk row).
  - `explanation` string, nullable: Server-side explanation text. Same disclosure rules as `correct_option` — only set when chain_terminated AND user_id.
  - `replayed` boolean, nullable: True on early-return paths (unauth-cap or prior-terminated-fail) where the server returns a cached terminal verdict instead of grading the new attempt.
  - `requires_signup` boolean, nullable: True only on the unauth-cap early-return path. Frontend uses this to flip to a sign-up CTA after the 2-anon-attempt cap.
  - `remediation` object, nullable: Adaptive Mastery System primer offer (sub-70 score, eligible source module). Shape rendered client-side by learning-paths.ts; opaque-to-SDK consumers.
  - `mastery_explanation` string, nullable: One-line hint explaining the 60% quiz / 40% apply-task weighting when a user aces the quiz on a module with an apply-task registered. PR5 audit fix (Wave 3 of AUDIT_TRIAGE_2026_05_06.md). None on modules without an apply-task registered (~180 of 222 modules).
  - `next_step_hint` string, nullable: Encouragement / next-step text rendered below the quiz result. Tone is calibration, never shame. Five branches: clean run, right-with-hint, right-on-attempt-N, chain-terminated-failed, can-retry. PR12 audit fix (Wave 3 of AUDIT_TRIAGE_2026_05_06.md).
  - `mastery_transitions` object[], nullable: T3.3 (S50 flip 2026-07-19): concept-layer crossings this submit caused — [{concept_slug, concept_title, from_layer, to_layer, direction, message}]. Advances carry copy.py advance_copy (quiet completion line + unlock-toast recheck); regressions carry the marked-for-review line. Additive/optional — absent when no layer crossed.
  - `module_id` string, nullable: The canonical module id this submit was graded against, after slug resolution. Present on every graded (200) response; learn-module.ts keys client progress by it, because edge-cached SSR lesson HTML may still POST the lesson slug (2026-10-17). Declared here so the OpenAPI spec and the typed client carry it rather than relying on extra='allow'.

---

[API](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api.md) · [All operations](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/llms.txt) · [OpenAPI document](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/revisions/e832a1260f0b?raw)
