QuizBuilder Live turns any multiple-choice or true/false test into a real-time competitive trivia game. Players join from any browser — no app or account required. The host controls the pace question by question; speed-weighted scoring keeps every round competitive.
multiple_choice or true_false question.short_text, long_text, etc.) are silently skipped during the live game.A live game progresses through these states in order:
waiting → question_active → question_closed → ... → finished
| State | Description |
|---|---|
waiting |
Lobby — players can join; host has not started yet |
question_active |
A question is visible; the countdown timer is running |
question_closed |
Timer expired or host closed the question; correct answer and scores are revealed |
finished |
All questions have been shown; final leaderboard is available |
For each correct answer:
points = question.points × 1000 × (0.5 + 0.5 × (1 − time_ms / time_limit_ms))
question.points × 1000 (instant answer)question.points × 500 (answered in the last millisecond)Points are calculated server-side using the server-recorded receive time — client clock skew and network latency do not affect fairness.
/live-join on their device and entering the PIN, or by scanning the QR code.All live game endpoints are under /api/v1/live/.
POST /api/v1/live/games
Authorization: Bearer <token>
Content-Type: application/json
{
"test_id": "<uuid>",
"time_limit_seconds": 20
}
time_limit_seconds defaults to 20; clamped to the range [5, 120].id, pin, and initial state waiting.Response:
{
"id": "...",
"pin": "123456",
"state": "waiting",
"test_id": "...",
"time_limit_seconds": 20
}
Public endpoint — no authentication required.
POST /api/v1/live/join
Content-Type: application/json
{
"pin": "123456",
"nickname": "Alice"
}
Response:
{
"player_id": "<uuid>",
"game_id": "<uuid>",
"nickname": "Alice"
}
Save player_id — it is required to submit answers and retrieve results.
Public endpoint. Poll at ~1 s intervals to drive the player and host UIs.
GET /api/v1/live/games/{game_id}/state
Response shape:
{
"state": "question_active",
"current_question": {
"id": "...",
"prompt_json": { ... },
"options_json": [
{ "id": "a", "content_json": { ... } },
{ "id": "b", "content_json": { ... } }
],
"points": 1,
"time_limit_seconds": 20,
"started_at": "<ISO timestamp>"
},
"players": [
{ "player_id": "...", "nickname": "Alice", "score": 0 }
],
"question_index": 0,
"question_total": 10
}
When state is question_closed the response also includes correct_answer and per-player scores for the closed question. When state is finished it includes the final leaderboard sorted by score descending.
Public endpoint. Must be submitted while the question is question_active.
POST /api/v1/live/games/{game_id}/answer
Content-Type: application/json
{
"player_id": "<player_id from join>",
"value": { "selected": "b" }
}
value.selected is the option id (e.g. "a", "b", "true", "false").{"ok": true}.Authenticated endpoint. Moves from question_closed → question_active (next question), or from question_closed → finished after the last question.
Also callable during waiting to start the game (moves to question_active for the first question).
POST /api/v1/live/games/{game_id}/next
Authorization: Bearer <token>
Authenticated endpoint. Moves from question_active → question_closed. The correct answer is revealed and scores are computed. If the timer has already expired the server auto-closes the question; this call is idempotent.
POST /api/v1/live/games/{game_id}/close
Authorization: Bearer <token>
Public endpoint. Returns the player’s answer, correctness, and points earned for a specific question.
GET /api/v1/live/games/{game_id}/player/{player_id}/result?question_id={question_id}
Response:
{
"player_id": "...",
"question_id": "...",
"value": { "selected": "b" },
"correct": true,
"points_earned": 876,
"cumulative_score": 1742,
"rank": 3
}
1. POST /live/games → get game_id, pin
2. Display PIN + QR code
3. Poll GET /live/games/{id}/state (every 1 s) → show player list
4. POST /live/games/{id}/next → start game
5. Poll state → show current question + countdown
6. POST /live/games/{id}/close → reveal answer + leaderboard
7. POST /live/games/{id}/next → next question (or → finished)
8. Repeat 5–7 until state = finished
1. POST /live/join → get player_id
2. Poll GET /live/games/{id}/state (every 1 s) → wait in lobby
3. When state = question_active → display question
4. POST /live/games/{id}/answer → submit answer
5. When state = question_closed → show result + rank
6. Repeat 3–5 until state = finished
| Limit | Value |
|---|---|
| Minimum time limit | 5 seconds |
| Maximum time limit | 120 seconds |
| Supported question types | multiple_choice, true_false |
| Questions skipped | multiple_select, short_text, long_text, file_upload, and informational types |