Skip to content

Quizzes

Manage quizzes, or generate new ones with AI.

OperationEndpointScope
List quizzesGET /api/v1/quizzesapi:quiz:read
Create a quizPOST /api/v1/quizzesapi:quiz:write
Get a quizGET /api/v1/quizzes/{quizId}api:quiz:read
Replace a quizPUT /api/v1/quizzes/{quizId}api:quiz:write
Update a quizPATCH /api/v1/quizzes/{quizId}api:quiz:write
Delete a quizDELETE /api/v1/quizzes/{quizId}api:quiz:write
Generate a quizPOST /api/v1/quizzes/generateapi:quiz:write
Poll an async generationGET /api/v1/quizzes/generate/{requestId}api:quiz:read
List a quiz's assignmentsGET /api/v1/quizzes/{quizId}/assignmentsapi:assignment:read

List quizzes

GET /api/v1/quizzes
json
{
  "data": [
    { "id": "…", "content": { "…": "…" }, "image_url": null,
      "created_at": "…", "updated_at": "…" }
  ]
}

Create a quiz

POST /api/v1/quizzes
FieldTypeRequiredNotes
contentobjectYesQuiz content (questions, options, answers).
image_urlstringNoCover image URL.

content is validated against the quiz rules; invalid content returns 400. The number of questions must fit your plan's per-quiz limit, else 400 with code: "QUESTION_LIMIT_EXCEEDED".

json
{ "data": { "id": "…" } }   // 201

Get / replace / update / delete

GET    /api/v1/quizzes/{quizId}     →  { "data": { …quiz } }   (404 if not found)
PUT    /api/v1/quizzes/{quizId}     →  body { content, image_url? }  →  { "data": { "id": "…" } }
PATCH  /api/v1/quizzes/{quizId}     →  body { content?, image_url? } →  { "data": { "id": "…" } }
DELETE /api/v1/quizzes/{quizId}     →  { "data": { "deleted": true } }

PUT replaces content (and image when supplied); PATCH updates only the fields present.

Generate a quiz

POST /api/v1/quizzes/generate

Generates a quiz with AI, saves it, and returns its ID. Runs non-streaming and does not produce a cover image.

FieldTypeNotes
targetLanguage"ja" | "zh-TW"Quiz language.
sourceMode"text" | "image" | "mixed" | "instruction"Defaults to text.
textSourcestringRequired for text / mixed.
imageUrl / imageUrlsstring / string[]Required for image / mixed. Public image URLs.
proficiencyLevelstringJLPT (N5–N1), TOCFL, or CEFR level.
difficulty"easy" | "medium" | "hard"Difficulty within the level.
teacherInstructionsstringOptional steering text.
topicstringOptional topic for instruction mode.
json
{
  "data": {
    "quiz_id": "…",
    "title": "…",
    "question_count": 10,
    "target_language": "ja",
    "tokens_used": 1234
  },
  "requestId": "…"
}

A 402 with upgrade_url indicates your generation quota is exhausted.

Asynchronous generation

Generation can take tens of seconds. To avoid client/proxy timeouts on slow generations, set async: true (or mode: "async") in the request body. The endpoint validates the request, enqueues a background job, and returns 202 immediately with a request_id — it does not wait for the quiz:

json
{ "data": { "request_id": "…" } }   // 202

Validation still happens synchronously, so an invalid request fails fast with the same 4xx it would return in sync mode (nothing is enqueued).

Then poll for the result:

GET /api/v1/quizzes/generate/{requestId}      // scope: api:quiz:read
json
{ "data": { "status": "processing", "request_id": "…" } }
{ "data": { "status": "success", "request_id": "…", "quiz_id": "…",
            "question_count": 10, "target_language": "ja", "tokens_used": 1234 } }
{ "data": { "status": "failed", "request_id": "…", "error": "…" } }

Poll until status is success or failed. An unknown requestId (or one belonging to another account) returns 404.

List a quiz's assignments

GET /api/v1/quizzes/{quizId}/assignments?page=1&limit=20&status=

Lists the assignments created under a quiz you own (same response shape and paging as GET /api/v1/assignments). Returns 404 if the quiz does not exist or is not yours.

QueryDefaultNotes
page11–1000.
limit201–100.
statusFilter by status.

TechTrans Lab