Quizzes
A quiz is a set of graded, choice-only questions. Managing a quiz — including reading attempts — requires your API key.
Scoring is exact-match, all-or-nothing per question — there is no partial credit. A question can have more than one correct choice (select-all-that-apply); it only counts toward the score if the submitted set of choices exactly matches the correct set. Selecting only some of the correct choices, or a correct choice plus an extra wrong one, both score that question as incorrect.
A quiz attempt's answers embed is_correct and the exact choices selected, which is effectively the answer key, so attempt results are never public — only submitting an attempt is. See Quiz Attempts.
| Method | Endpoint | Description |
|---|---|---|
| POST | /quizzes | Create a quiz |
| GET | /quizzes | List all of your quizzes |
| GET | /quizzes/identifier/{identifier} | Get one of your quizzes by its identifier |
| GET | /quizzes/{quiz} | Get one of your quizzes by ID |
| PATCH | /quizzes/{quiz} | Update a quiz (PUT also accepted) |
| DELETE | /quizzes/{quiz} | Delete a quiz (also deletes its questions, choices, attempts, and answers) |
/quizzes
API key
Create a quiz
| Field | Type | Rules |
|---|---|---|
| identifier | string | Optional, same rules as Poll's identifier — unique per account. Generated from title if omitted. |
| title | string | Required, max 255 |
| description | string | Optional |
| metadata | object | Optional, freeform — same as Poll's metadata |
| site_id | integer | Optional, same rules as Poll's site_id |
| requires_captcha | boolean | Optional, same rules as Poll's requires_captcha — see Quiz Attempts. |
| is_closed | boolean | Optional, same rules as Poll's is_closed — see Quiz Attempts. |
| response_limit | integer | Optional, nullable, minimum 1, same rules as Poll's response_limit. |
| questions | array | Required, at least 1 |
| questions[].prompt | string | Required |
| questions[].choices | array | Required, at least 2, labels must be unique within that question |
| questions[].choices[].label | string | Required, max 255 |
| questions[].choices[].is_correct | boolean | Required — at least one choice per question must be true |
curl -X POST https://qnaapi.com/api/v1/quizzes \
-H "X-API-Key: qna_..." \
-H "Content-Type: application/json" \
-d '{
"identifier": "js-basics",
"title": "JavaScript Basics",
"questions": [
{
"prompt": "Which are primitive types in JS?",
"choices": [
{ "label": "string", "is_correct": true },
{ "label": "object", "is_correct": false },
{ "label": "number", "is_correct": true }
]
},
{
"prompt": "What is 2 + 2?",
"choices": [
{ "label": "3", "is_correct": false },
{ "label": "4", "is_correct": true }
]
}
]
}'{
"data": {
"id": 1,
"identifier": "js-basics",
"title": "JavaScript Basics",
"description": null,
"metadata": null,
"site_id": null,
"requires_captcha": false,
"is_closed": false,
"response_limit": null,
"is_accepting_responses": true,
"questions": [
{
"id": 1,
"prompt": "Which are primitive types in JS?",
"position": 0,
"choices": [
{ "id": 1, "label": "string", "is_correct": true },
{ "id": 2, "label": "object", "is_correct": false },
{ "id": 3, "label": "number", "is_correct": true }
]
},
{
"id": 2,
"prompt": "What is 2 + 2?",
"position": 1,
"choices": [
{ "id": 4, "label": "3", "is_correct": false },
{ "id": 5, "label": "4", "is_correct": true }
]
}
],
"created_at": "2026-08-15T01:25:24.000000Z",
"updated_at": "2026-08-15T01:25:24.000000Z"
}
}is_accepting_responses is read-only and computed on every response — false whenever is_closed is true or the quiz's attempt count has reached response_limit. Toggle is_closed/response_limit instead of trying to set it directly.
/quizzes, /quizzes/{quiz}, /quizzes/identifier/{identifier}
API key
List / get by ID / get by identifier
Same shape as the equivalent Poll endpoints, scoped to your own quizzes.
curl -H "X-API-Key: qna_..." https://qnaapi.com/api/v1/quizzes
/quizzes/{quiz}
API key
Update a quiz
Every field is optional. questions (with their choices) can be replaced using the same shape and validation rules as create — but only while the quiz has zero attempts. site_id, requires_captcha, is_closed, and response_limit can be changed at any time.
curl -X PATCH https://qnaapi.com/api/v1/quizzes/1 \
-H "X-API-Key: qna_..." \
-H "Content-Type: application/json" \
-d '{ "title": "JavaScript Fundamentals" }'questions in an update is rejected (422), for the same reason Poll options lock after the first vote: changing them would silently invalidate existing scores. Delete and recreate the quiz if the questions need to change after that point.
/quizzes/{quiz}
API key
Delete a quiz
curl -X DELETE -H "X-API-Key: qna_..." https://qnaapi.com/api/v1/quizzes/1
204 No Content on success. Cascades — questions, choices, attempts, and answers are all removed too.