---
title: "Get Quiz History"
method: GET
path: "/knowledge-quiz/courses/{course_id}/history"
tags: ["knowledge-quiz"]
---

# Get Quiz History

`GET /knowledge-quiz/courses/{course_id}/history`

Get the student's quiz attempt history for a course.

## Path parameters

- `course_id` string, required

## Query parameters

- `assignment_id` string, required

## Response `200`

Successful Response

- QuizHistoryResponse — Response for quiz attempt history.
  - `attempts` AttemptResponse[], required
    - `id` string, required
    - `quiz_id` string, required
    - `student_id` string, required
    - `course_id` string, required
    - `assignment_id` string, required
    - `status` string, required
    - `score_out_of_20` number, required
    - `correct_count` integer, required
    - `total_questions` integer, required
    - `attempt_number` integer, required
    - `started_at` string, date-time, required
    - `completed_at` string, date-time, nullable
    - `answers` QuizAnswerRecord[]
      - `question_id` string, required
      - `answer_type` 'choice' | 'open'
      - `selected_answer_index` integer, nullable
      - `is_correct` boolean
      - `photo_urls` string[]
      - `grading_status` 'processing' | 'graded' | 'error' | 'rejected', nullable
      - `grading_error` string, nullable
      - `rubric_evaluation` RubricEvaluation — One evaluation pass over a submission against a specific rubric. Multiple may exist per submission attempt (initial AI + teacher overrides); the latest one is canonical.
        - `rubric_id` string, required
        - `author` union, required
          - AIAuthor
            - `type` 'ai'
            - `prompt_id` string, required
            - `model` string, nullable
          - HumanAuthor
            - `type` 'human'
            - `user_id` string, required
        - `feedback` string, required
        - `questions` RubricQuestionEvaluation[], required
          - `skill_outcomes` SkillOutcome[], required
            - `savoir_faire_id` string, required
            - `outcome` 'correct' | 'partial' | 'wrong' | 'unanswered', required
            - `note` string, required
            - `evidence` EvidenceSpan[], required
              - …
          - `criterion_outcomes` CriterionOutcome[]
            - `criterion_index` integer, required
            - `outcome` 'correct' | 'partial' | 'wrong' | 'unanswered', required
            - `note` string, required
            - `evidence` EvidenceSpan[], required
              - …
            - `student_label` string, nullable
            - `student_note` string, nullable
          - `question_outcome` QuestionOutcome — The grader's verdict on one question of a points rubric: where the answer sits on the five-level ladder, plus what the student is told. `unanswered` is not a rung on the ladder — it says there was nothing on the page to grade (on the photo path it also covers "this part of the copy is unreadable", so illegibility is never laundered into a low score). It implies `score == 0`, which `validate_question_evals_match_rubric` enforces. `alternative_method` records that the route read on the copy is not the corrigé's. It is informational — a valid alternative route scores 4 like any other correct answer — but it is the signal that says whether the scheme is doing the job it was built for. `teacher_points_awarded` is the mark a human wrote on this question (EXC-765). It is `None` on every AI-authored outcome, which is the whole back catalogue, and when it is set it is what the question earns — `question_award` is the one place that arbitration happens. A teacher grades in quarter-points against an allocation ("2,5 sur 3"), a shape the 0..4 ladder cannot express, so the figure is stored rather than folded back into a rung. The rung is still kept coherent with it: the override service re-derives `score` through `score_for_award` so the label, the v2 projection and the analytics never contradict the mark on the copy.
            - `score` integer, required
            - `unanswered` boolean
            - `note` string, required
            - `evidence` EvidenceSpan[]
              - …
            - `alternative_method` boolean
            - `teacher_points_awarded` number, nullable
          - `errors` FlaggedError[], required
            - `description` string, required
            - `evidence` EvidenceSpan[], required
              - …
            - `categories` ErrorCategory[], nullable
          - `carried_from_attempt` integer, nullable
        - `question_zones` QuestionZone[]
          - `question_indexes` integer[], required
          - `boxes` PhotoBBox[], required
            - `photo_index` integer, required
            - `x` number, required
            - `y` number, required
            - `width` number, required
            - `height` number, required
        - `computed_grade` number, required
        - `max_grade` number, required
        - `evaluated_at` string, date-time, required
        - `carried_photo_urls` string[]
      - `points_earned` number
      - `points_max` number
  - `best_score` number, required
  - `attempts_count` integer, required
  - `max_attempts` integer, nullable
  - `can_retry` boolean, required
  - `quiz_start_date` string, date-time, nullable
  - `quiz_end_date` string, date-time, nullable
  - `is_enabled` boolean
  - `is_open` boolean

## Other responses

- `422` — Validation Error

## Changes

> 23 revisions in range; 1 not diffed.

- **2026-09-25** `a8ae0e0c0570` — 2 info
  - added the optional property `attempts/items/answers/items/rubric_evaluation/anyOf[subschema #1: RubricEvaluation]/carried_photo_urls` to the response with the `200` status
  - added the optional property `attempts/items/answers/items/rubric_evaluation/anyOf[subschema #1: RubricEvaluation]/questions/items/carried_from_attempt` to the response with the `200` status
- **2026-09-24** `957b18a69df8` — 2 info
  - added the optional property `attempts/items/answers/items/rubric_evaluation/anyOf[subschema #1: RubricEvaluation]/questions/items/criterion_outcomes/items/student_label` to the response with the `200` status
  - added the optional property `attempts/items/answers/items/rubric_evaluation/anyOf[subschema #1: RubricEvaluation]/questions/items/criterion_outcomes/items/student_note` to the response with the `200` status
- **2026-09-22** `05e048df94c6` — 1 breaking, 1 info
  - the response property `attempts/items/answers/items/rubric_evaluation/anyOf[subschema #1: RubricEvaluation]/questions/items/criterion_outcomes` became optional for the status `200`
  - added the optional property `attempts/items/answers/items/rubric_evaluation/anyOf[subschema #1: RubricEvaluation]/questions/items/question_outcome` to the response with the `200` status
- …earlier changes not shown

[Full history](https://skmtc.dev/excellence-ai/apis/excellence-learning/changes/knowledge-quiz/courses/:course_id/history/get.md)

---

[API](https://skmtc.dev/excellence-ai/apis/excellence-learning.md) · [All operations](https://skmtc.dev/excellence-ai/apis/excellence-learning/llms.txt) · [OpenAPI document](https://skmtc.dev/excellence-ai/apis/excellence-learning/revisions/a8ae0e0c0570?raw)
