# Quizzes A quiz is user-generated content like a gist or a project: it has an owner, a slug, comments, votes, bookmarks and reactions. Any signed-in member authors quizzes, every member plays them, and guests read published ones. **Publishing is terminal.** A draft is fully editable; the moment its owner publishes it, the quiz, its questions and its options are frozen forever. There is no unpublish and no post-publish edit, which is what makes two members' scores on the same quiz comparable. Every write endpoint on a published quiz returns `400`; only delete still works. Publish validates the whole quiz first and refuses with the exact list of problems. Playing a quiz creates an **attempt**. There is at most one in-progress attempt per member per quiz - starting again returns the existing one. Each question can be answered exactly once; a second submit returns `400` and credits nothing. A time limit is stored on the attempt and evaluated lazily on read, so an expired attempt reads as `expired` with no background process involved. Seven question kinds are graded deterministically. The eighth, `free_text`, is graded by the internal AI gateway against the author's criteria and billed to the answering member's own API key. When the gateway is unavailable the answer is still graded, by a deterministic token-overlap fallback, and the answer carries `graded_by: "fallback"` so the degradation is visible rather than silent. `graded_by` is one of `auto`, `ai`, `fallback`. **Correct answers are never served to a player mid-attempt.** `is_correct` on the options and `correct_boolean` / `expected_answer` / `numeric_value` / `match_value` on the question are omitted unless the viewer owns the quiz, or the question has already been answered in this attempt and the quiz has `reveal_answers` on. A public export of a published quiz omits them too; the owner's export includes them. The **scoreboard** at `/quizzes/scoreboard` sums each member's **best** completed attempt per quiz, never the sum of all attempts, so replaying a quiz can raise a member's contribution to their personal best and never beyond it. Quizzes a member wrote themselves count like any other. All endpoints negotiate HTML or JSON. POST bodies are form encoded (`application/x-www-form-urlencoded`). Action POSTs answer `{"ok": true, "redirect": "...", "data": {...}}`; an invalid domain operation answers `400` as `{"error": {"status": 400, "message": "..."}}`.
GET /quizzes Minimal role: Public

Quiz hub

Published quizzes with the viewer's per-quiz state, the filter counts and the cross-quiz scoreboard.

GET /quizzes/scoreboard Minimal role: Public

Quiz scoreboard

Score per user across every published quiz, counting each member's best attempt per quiz. Cached about 15 seconds.

GET /quizzes/new Minimal role: Member

New quiz form

The create form behind the New quiz button.

POST /quizzes/create Minimal role: Member

Create a quiz

Create a draft quiz. Add its questions afterwards, then publish it.

POST /quizzes/import Minimal role: Member

Import a quiz document

Create a complete quiz - metadata, settings, every question and every option - from one JSON document. Capped at 100 questions and 12 options per question.

GET /quizzes/{slug} Minimal role: Public

Quiz detail

One quiz with its stats, its leaderboard, its comments and the viewer's own state. A draft is visible only to its owner and to administrators.

GET /quizzes/{slug}/export Minimal role: Public

Export a quiz

The full quiz document, the exact inverse of the import endpoint. The owner gets every correct answer; everyone else gets the questions without the key.

GET /quizzes/{slug}/leaderboard Minimal role: Public

Quiz leaderboard

Top completed attempts on one quiz, best percentage first.

GET /quizzes/{slug}/edit Minimal role: Member

Quiz builder

The owner's builder page: the quiz, every question with its answer key, the question-kind catalogue and the live pre-publish checklist.

POST /quizzes/edit/{slug} Minimal role: Member

Edit a quiz

Change the title, description and settings of a DRAFT quiz. 400 once published.

POST /quizzes/{slug}/publish Minimal role: Member

Publish a quiz

IRREVERSIBLE. Freezes the quiz, its questions and its options forever. Refuses with the validation problems when the quiz is incomplete.

POST /quizzes/delete/{slug} Minimal role: Member

Delete a quiz

Owner or administrator. Removes the quiz with its questions, options, attempts and answers. The only operation left on a published quiz.

POST /quizzes/{slug}/questions Minimal role: Member

Add a question

Append one question with its options to a DRAFT quiz. 400 once published.

POST /quizzes/{slug}/questions/{question_uid} Minimal role: Member

Edit a question

Replace one question and its options on a DRAFT quiz. 400 once published.

POST /quizzes/{slug}/questions/{question_uid}/delete Minimal role: Member

Delete a question

Remove one question and its options from a DRAFT quiz, then renumber.

POST /quizzes/{slug}/questions/reorder Minimal role: Member

Reorder the questions

Set a new question order on a DRAFT quiz. Every uid must be listed exactly once.

POST /quizzes/{slug}/attempts Minimal role: Member

Start or resume an attempt

Returns the member's single in-progress attempt, creating it when there is none. The question order and one blank answer row per question are materialized at start.

GET /quizzes/{slug}/attempts/{attempt_uid} Minimal role: Member

Read an attempt

The attempt with its questions in play order. Correct answers are withheld until a question is answered and the quiz reveals answers.

POST /quizzes/{slug}/attempts/{attempt_uid}/answer Minimal role: Member

Answer a question

Grade and record one answer. Each question can be answered exactly once; a second submit answers 400 and credits nothing.

POST /quizzes/{slug}/attempts/{attempt_uid}/finish Minimal role: Member

Finish an attempt

Close the attempt and compute the final score from its answer rows. A second finish returns the same result and awards nothing again.

GET /quizzes/{slug}/attempts/{attempt_uid}/results Minimal role: Member

Attempt results

The result of one attempt: score, percentage, pass verdict, and the per-question review when the author allowed it. Attempt owner or admin.