quiz-taking

9 endpoints.

GET/api/quizzes/assigned Bearer token

List my assigned quizzes

Every published quiz assigned to the caller — individually, or through any unexpired grant of an assigned role — with where they stand on each: the current and next scheduled sittings they may sit (a roster sitting counts only for those on its roster), attempts used, the open attempt to resume, and the latest result once results are visible. Needs no permission grant: being assigned is the authorization.

Responses

StatusDescriptionBody
200The caller's assigned quizzes, newest first.AssignedQuizList
401The access token is missing or invalid.ErrorResponse
500The database could not be read.ErrorResponse
POST/api/quizzes/{quiz_id}/attempts Bearer token

Start (or resume) an attempt

Starts an attempt of an assigned, published quiz that is takeable right now — inside an open sitting for live quizzes (one open to every assignee, or a roster sitting the caller is on), any time for async ones. The paper is drawn per the quiz's selection mode, persisted, and served with the answers stripped. An attempt already in progress is returned instead of starting another (200, not 201). Refused outside a sitting, or once max_attempts is used up — counted within the current sitting for live quizzes, per quiz for async. Needs no permission grant: being assigned is the authorization.

Parameters

NameInTypeRequiredDescription
quiz_idpathstringyesUUID id, or a slug resolved within the organization given by the org query parameter.
orgquerystringnoOrganization UUID id or slug to filter by (and to resolve slug refs in).

Responses

StatusDescriptionBody
200The attempt already in progress, resumed.QuizAttemptDetail
201The freshly started attempt and its paper.QuizAttemptDetail
401The access token is missing or invalid.ErrorResponse
404No quiz assigned to the caller has that id or slug.ErrorResponse
409No sitting is open, no attempts remain, or the paper is empty.ErrorResponse
500The database could not be reached, or the write failed.ErrorResponse
GET/api/quiz-attempts/{attempt_id}/questions/{question_id}/pdf Bearer token

Get a download URL for a presented question's PDF

Issues a short-lived presigned GET for the PDF of a pdf question this attempt presented — while sitting the attempt and in answer review alike. Readable by the taker themselves, and by holders of quizzes:read over the quiz. Carries no answers.

Parameters

NameInTypeRequiredDescription
attempt_idpathstring (uuid)yesUUID id of the attempt.
question_idpathstring (uuid)yesUUID id of the question.

Responses

StatusDescriptionBody
200Where to fetch the PDF from, for the next five minutes.DownloadTicket
401The access token is missing or invalid.ErrorResponse
404No visible attempt has that id, the question is not on its paper, or it has no PDF.ErrorResponse
500The download URL could not be signed.ErrorResponse
503File storage is not configured on this deployment.ErrorResponse
GET/api/quiz-attempts/{attempt_id}/review.csv Bearer token

Download an attempt's answers as CSV

The attempt's graded paper as one CSV file, one row per presented question in presentation order, with the columns `attempt_id`, `quiz_id`, `quiz_name`, `user_id`, `user_display_name`, `attempt_number`, `status`, `started_at`, `submitted_at`, `auto_submitted`, `score_percentage`, `passed`, `position`, `question_id`, `kind`, `prompt`, `response`, `correct_answer`, `is_correct`, `points_awarded`, `points_possible`, `feedback`, `answered_at`. Lists in a cell are `; `-separated, alternative accepted spellings `|`-separated, matched pairs read `left → right`, and the file opens with a UTF-8 byte order mark for spreadsheets. Takers may download their own scored attempt once its results are visible and the quiz shows correct answers; holders of quizzes:read or quizzes:grade over the quiz may download any attempt, in progress or not.

Parameters

NameInTypeRequiredDescription
attempt_idpathstring (uuid)yesUUID id of the attempt.

Responses

StatusDescriptionBody
200The CSV file, served as an attachment.—
401The access token is missing or invalid.ErrorResponse
403Review is not (or not yet) available to the taker for this quiz.ErrorResponse
404No visible attempt has that id.ErrorResponse
500The database could not be read.ErrorResponse
GET/api/quiz-attempts/{attempt_id}/review.json Bearer token

Download an attempt's answers as JSON

The attempt's graded paper — exactly the review endpoint's document — served as a JSON attachment. Takers may download their own scored attempt once its results are visible and the quiz shows correct answers; holders of quizzes:read or quizzes:grade over the quiz may download any attempt, in progress or not.

Parameters

NameInTypeRequiredDescription
attempt_idpathstring (uuid)yesUUID id of the attempt.

Responses

StatusDescriptionBody
200The JSON file, served as an attachment.QuizAttemptReview
401The access token is missing or invalid.ErrorResponse
403Review is not (or not yet) available to the taker for this quiz.ErrorResponse
404No visible attempt has that id.ErrorResponse
500The database could not be read.ErrorResponse
GET/api/quiz-attempts/{attempt_id}/review Bearer token

Review an attempt's answers

The attempt's paper with correct answers, the taker's responses and per-question grades — points awarded and possible, the marker's feedback, and the rubric where the reader may see it. Takers see it only once the attempt is scored, its results are visible, and the quiz is configured to show correct answers; holders of quizzes:read or quizzes:grade over the quiz always may, with the rubric and the machine's suggestion on manually graded questions. Questions render as they are *now* — an edit after the sitting changes the review, never the recorded grades. The same paper downloads as a file from the sibling review.csv and review.json paths.

Parameters

NameInTypeRequiredDescription
attempt_idpathstring (uuid)yesUUID id of the attempt.

Responses

StatusDescriptionBody
200The graded paper, answers included.QuizAttemptReview
401The access token is missing or invalid.ErrorResponse
403Review is not (or not yet) available to the taker for this quiz.ErrorResponse
404No visible attempt has that id.ErrorResponse
500The database could not be read.ErrorResponse
GET/api/quiz-attempts/{attempt_id} Bearer token

Read an attempt

The attempt and its paper, answers stripped — the taking and resume view. Readable by the taker themselves, and by holders of quizzes:read over the quiz. An attempt past its deadline is finalized (auto-submitted as-is) by this read. Held-back results are nulled for the taker until released; permission holders always see them.

Parameters

NameInTypeRequiredDescription
attempt_idpathstring (uuid)yesUUID id of the attempt.

Responses

StatusDescriptionBody
200The attempt and its paper.QuizAttemptDetail
401The access token is missing or invalid.ErrorResponse
404No visible attempt has that id.ErrorResponse
500The database could not be read.ErrorResponse
POST/api/quiz-attempts/{attempt_id}/answers Bearer token

Answer one question

Saves (or replaces) the taker's answer to one presented question, in the shape its kind takes: response_boolean (true_false), selected_option_ids (multiple_choice takes exactly one id; multi_select the chosen ids; ordering every presented item in the taker's arrangement), response_text (short_answer), response_number (numeric), response_matches (matching; partial pair lists are fine), response_blanks (fill_in_blank; one entry per blank, empty ones allowed) or response_drawing (drawing; the canvas as an image data URL). Only the taker may answer, only while the attempt is in progress and its deadline has not passed. Answers are not graded here; grading happens at submit.

Parameters

NameInTypeRequiredDescription
attempt_idpathstring (uuid)yesUUID id of the attempt.

Request body

application/jsonrequiredAnswerQuizQuestionRequest
FieldTypeRequiredDescription
question_idstring (uuid)yes—
response_booleanbooleanno—
selected_option_idsarray of string (uuid)no

multiple_choice: exactly one id. multi_select: the chosen ids. ordering: every presented item id, in the taker's arrangement.

1–20 items

response_textstringno

short_answer: up to 500 characters. long_answer: up to 20000.

1–20000 characters

response_numbernumberno—
response_matchesarray of ResponseMatchno

1–10 items

response_blanksarray of stringno

fill_in_blank: one entry per blank of the prompt, in order; leave an entry empty for a blank not yet filled, but fill at least one.

1–10 items

response_drawingstringno

drawing: the taker's canvas as one image — the starting image, if any, beneath their strokes — as a base64 data URL (image/png, image/webp or image/jpeg).

at most 4000000 characters · matches ^data:image\/(png|webp|jpeg);base64,[A-Za-z0-9+/]+=*$

Responses

StatusDescriptionBody
200The attempt with the saved answer.QuizAttemptDetail
400The answer does not fit the question's kind or options.ErrorResponse
401The access token is missing or invalid.ErrorResponse
404No visible attempt has that id, or the question is not on its paper.ErrorResponse
409The attempt is already submitted, or its deadline has passed.ErrorResponse
500The database could not be reached, or the write failed.ErrorResponse
POST/api/quiz-attempts/{attempt_id}/submit Bearer token

Submit an attempt

Grades the attempt server-side, scores it against the quiz's pass mark, and reports it into the taker's learning record for the quiz. Unanswered questions score zero. A paper holding a manually graded question lands in pending_grading instead: a marker awards its points and finalizes it, and an administrator releases the result. Submitting twice is safe — the second call returns the attempt as it stands. Score and pass/fail travel back only when the quiz's rules make results visible.

Parameters

NameInTypeRequiredDescription
attempt_idpathstring (uuid)yesUUID id of the attempt.

Responses

StatusDescriptionBody
200The submitted attempt; results nulled while withheld.QuizAttempt
401The access token is missing or invalid.ErrorResponse
404No visible attempt has that id.ErrorResponse
500The database could not be reached, or the write failed.ErrorResponse