Create Test

Generate an AI-powered test (quiz/assessment) from a prompt and receive a shareable test link.

POST /v1/platform/tests

Creates a test request. The AI model generates a structured test with questions of mixed types (multiple choice, true/false, fill-in-the-blank, open-ended), creates the test in TutorFlow, and returns preview and public URLs.

Tiers

The tier field selects the quality and pricing contract for the request. If omitted, TutorFlow defaults to standard:

TierPrice
basic$0.05
standard$0.15
advanced$0.25

TutorFlow stores a price snapshot at request time so billing remains consistent even if pricing is updated later.

Item Types

The AI generates a mix of the following item types based on the prompt:

TypeDescriptionAuto-graded
selectMultiple choice (one correct answer from options)Yes
true-falseTrue/false questionYes
blankFill-in-the-blank (exact-match grading)Yes
open-endedFree-form written responseNo (manual review)

select items always include an options array. true-false, blank, and open-ended items have options: null.

Request Body

FieldTypeRequiredDescription
promptstringYesPrompt describing the test to generate
titlestringNoOverride AI-generated title
descriptionstringNoOverride AI-generated description
languagestringNoTest language (default: en)
levelstringNoDifficulty hint (e.g. easy, medium, hard)
subjectstringNoSubject area (e.g. mathematics, physics, programming)
itemCountnumberNoTarget number of items for AI to generate
timeLimitnumberNoTime limit in minutes (default: 60, min: 1)
classroomIdstringNoClassroom ID to create the test in. Uses the default classroom if omitted
tierstringNobasic, standard, or advanced. Defaults to standard
idempotencyKeystringNoPrevents duplicate processing. Can also be sent via Idempotency-Key HTTP header
modestringNosync (default) or async

Example Request

curl -X POST https://api.tutorflow.io/v1/platform/tests \
  -H "Authorization: Bearer tf_platform_..." \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Create a 10-question quiz on basic algebra covering linear equations and inequalities",
    "language": "en",
    "level": "medium",
    "itemCount": 10,
    "timeLimit": 30
  }'

Response Fields

FieldTypeDescription
idstringPlatform test request ID
statusstringPENDING, PROCESSING, COMPLETED, or FAILED
classroomTestIdstring | nullActual test ID in TutorFlow (null until generation completes)
titlestring | nullTest title
descriptionstring | nullTest description
levelstring | nullDifficulty level (easy, medium, or hard)
timeLimitnumber | nullTime limit in minutes
totalScorenumber | nullSum of all item scores
itemCountnumber | nullNumber of items in the generated test
tierstringPricing tier used
priceSnapshotobject | nullPricing details captured at request time
itemsarray | nullItem summaries with sequence, type, question, options, score
shareTokenstring | nullToken used to construct preview and public URLs
previewUrlstring | nullEditor URL — /{locale}/platform/tests/{shareToken}
publicUrlstring | nullPublic test-taking URL — /{locale}/platform/tests/take/{shareToken}
isTerminalbooleanWhether the request has reached a final state
pollAfterMsnumber | nullRecommended polling interval for async requests
idempotencyKeystring | nullEchoed idempotency key
idempotentReplayboolean | nulltrue if this response reused an existing request, false for a fresh request, null when no idempotencyKey was provided
createdAtstringISO 8601 timestamp
completedAtstring | nullISO 8601 timestamp when generation completed

Example Response

{
  "id": "a1c2d3e4-f5g6-7h8i-9j0k-l1m2n3o4p5q6",
  "status": "COMPLETED",
  "classroomTestId": "c7d8e9f0-1a2b-3c4d-5e6f-7g8h9i0j1k2l",
  "title": "Basic Algebra Quiz",
  "description": "A 10-question quiz covering linear equations and inequalities.",
  "level": "medium",
  "timeLimit": 30,
  "totalScore": 100,
  "itemCount": 10,
  "tier": "standard",
  "priceSnapshot": {
    "category": "test_creation",
    "catalogKey": "test_creation.standard",
    "tier": "standard",
    "amountUsd": 0.15,
    "unit": "test",
    "currency": "USD",
    "source": "platform_pricing_catalog_v1"
  },
  "items": [
    {
      "sequence": 1,
      "type": "select",
      "question": "What is the solution to 2x + 3 = 11?",
      "options": ["x = 3", "x = 4", "x = 5", "x = 6"],
      "score": 10
    },
    {
      "sequence": 2,
      "type": "true-false",
      "question": "The inequality x > 5 includes the value 5.",
      "options": null,
      "score": 10
    },
    {
      "sequence": 3,
      "type": "blank",
      "question": "Solve for y: 3y = 21. y = ___",
      "options": null,
      "score": 10
    },
    {
      "sequence": 4,
      "type": "open-ended",
      "question": "Explain the difference between an equation and an inequality.",
      "options": null,
      "score": 10
    }
  ],
  "shareToken": "b018172542f9a3c4d5e6f7890abcdef12345678",
  "previewUrl": "https://tutorflow.io/en/platform/tests/b018172542f9a3c4d5e6f7890abcdef12345678",
  "publicUrl": "https://tutorflow.io/en/platform/tests/take/b018172542f9a3c4d5e6f7890abcdef12345678",
  "idempotencyKey": null,
  "idempotentReplay": null,
  "isTerminal": true,
  "createdAt": "2026-03-24T10:32:15.108Z",
  "completedAt": "2026-03-24T10:32:31.554Z"
}

Preview URL vs Public URL

URLPurposeAuthExpiry
previewUrlTest editor (title, description, items, answers)Public, no loginResolves an edit token server-side; the underlying token expires after 1h and is auto-refreshed on access
publicUrlPublic test-taking page for learnersPublic, no loginNone

The previewUrl is a link to /{locale}/platform/tests/{shareToken}, which resolves the latest edit token server-side and redirects into the editor. You do not need to refresh tokens manually before sharing the preview link. You can also mint a new edit token explicitly via POST /v1/platform/tests/:id/edit-token.

The publicUrl is the read-only link you share with learners. They land on the test intro page and start a submission by submitting their email (and optional name). See Submissions for the full taking flow.

Refreshing an Edit Token

curl -X POST https://api.tutorflow.io/v1/platform/tests/a1c2d3e4.../edit-token \
  -H "Authorization: Bearer tf_platform_..."
{
  "editToken": "new-token-hex...",
  "editTokenExpiresAt": "2026-03-24T13:30:00.000Z"
}

Edit Token API

The edit URL provides access to these public endpoints (no API key needed):

MethodPathDescription
GET/v1/platform/tests/edit/:editTokenGet test summary
GET/v1/platform/tests/edit/:editToken/fullGet full test with all items, correct answers, and explanations
GET/v1/platform/tests/edit/:editToken/items/:sequenceGet a single item (with answer)
PATCH/v1/platform/tests/edit/:editTokenUpdate test title, description, or time limit
PATCH/v1/platform/tests/edit/:editToken/items/:sequenceUpdate an item's question, options, correct answers, explanation, or score

Update Test

curl -X PATCH https://api.tutorflow.io/v1/platform/tests/edit/{editToken} \
  -H "Content-Type: application/json" \
  -d '{ "title": "Algebra Mid-Term", "timeLimit": 45 }'
FieldTypeRequiredDescription
titlestringNoUpdated test title
descriptionstringNoUpdated test description
timeLimitnumberNoUpdated time limit in minutes

Update Item

curl -X PATCH https://api.tutorflow.io/v1/platform/tests/edit/{editToken}/items/3 \
  -H "Content-Type: application/json" \
  -d '{
    "question": "Solve for y: 3y = 21",
    "correctAnswers": ["7"],
    "score": 15
  }'
FieldTypeRequiredDescription
questionstringNoUpdated question text
optionsarrayNoUpdated options (for select items)
correctAnswersarrayNoUpdated correct answer(s)
explanationstringNoUpdated explanation shown after submission
scorenumberNoUpdated point value for the item

Async Mode

Set mode: "async" to queue test generation as a background job. The response returns immediately with status: "PENDING" and a pollAfterMs value. Poll GET /v1/platform/tests/:id until isTerminal is true.

Idempotency

Pass an idempotencyKey in the request body or Idempotency-Key header to prevent duplicate test generation. Reusing the same key returns the original response with idempotentReplay: true.