Submissions

Take a test as a learner — start a submission, save answers, and retrieve graded results.

The submission flow lets learners take a test via the public shareToken without needing an API key. Submissions are uniquely identified per (test, email) pair, so returning to the test with the same email resumes any in-progress submission.

Flow Overview

  1. Load the test for takingGET /v1/platform/tests/public/:shareToken/take
  2. Start a submissionPOST /v1/platform/tests/public/:shareToken/submissions
  3. Save answers (optionally repeatedly)PATCH /v1/platform/tests/submissions/:submissionToken
  4. Submit final answers — same PATCH endpoint with isDone: true
  5. Retrieve the graded resultGET /v1/platform/tests/submissions/:submissionToken/result
  6. (Workspace) List all submissionsGET /v1/platform/tests/:id/submissions

GET /v1/platform/tests/public/:shareToken/take

Loads the test in taking mode. Item answers and explanations are not included.

Example Response

{
  "title": "Basic Algebra Quiz",
  "description": "A 10-question quiz covering linear equations and inequalities.",
  "level": "medium",
  "timeLimit": 30,
  "itemCount": 10,
  "totalScore": 100,
  "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
    }
  ]
}

POST /v1/platform/tests/public/:shareToken/submissions

Starts a new submission, or resumes an existing in-progress submission for the same email address.

Request Body

FieldTypeRequiredDescription
emailstringYesLearner email — used to identify and resume submissions
namestringNoOptional learner display name (≤ 200 chars)

Example Request

curl -X POST https://api.tutorflow.io/v1/platform/tests/public/{shareToken}/submissions \
  -H "Content-Type: application/json" \
  -d '{ "email": "alice@example.com", "name": "Alice" }'

Response

FieldTypeDescription
submissionIdstringInternal submission ID
submissionTokenstringToken used to submit answers and fetch the result
startedAtstringISO 8601 timestamp when the submission was first started
resumedbooleantrue if an existing in-progress submission was resumed
savedAnswersarray | nullPreviously saved answers (only present when resumed: true)
testobjectSame shape as GET /public/:shareToken/take

Example Response

{
  "submissionId": "5f6a7b8c-9d0e-1f2a-3b4c-5d6e7f8a9b0c",
  "submissionToken": "sub_b3f1a2c4d5e6f7890abcdef1234567890",
  "startedAt": "2026-03-24T11:00:00.000Z",
  "resumed": false,
  "test": {
    "title": "Basic Algebra Quiz",
    "description": "A 10-question quiz...",
    "level": "medium",
    "timeLimit": 30,
    "itemCount": 10,
    "totalScore": 100,
    "items": [
      { "sequence": 1, "type": "select", "question": "...", "options": ["..."], "score": 10 }
    ]
  }
}

PATCH /v1/platform/tests/submissions/:submissionToken

Saves answers for an in-progress submission. Call multiple times to save progress incrementally; call once with isDone: true to finalize and trigger grading.

Request Body

FieldTypeRequiredDescription
itemsarrayYesArray of { sequence, answers } objects
items[].sequencenumberYesItem sequence number
items[].answersstring[]YesLearner's answer(s) for the item
isDonebooleanNoSet to true to finalize the submission. Defaults to false

Example Request

curl -X PATCH https://api.tutorflow.io/v1/platform/tests/submissions/{submissionToken} \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "sequence": 1, "answers": ["x = 4"] },
      { "sequence": 2, "answers": ["false"] },
      { "sequence": 3, "answers": ["7"] },
      { "sequence": 4, "answers": ["An equation states two expressions are equal..."] }
    ],
    "isDone": true
  }'

Auto-Grading

When isDone: true, items are graded as follows:

Item TypeGrading
selectAuto-graded — exact match against correctAnswers
true-falseAuto-graded — exact match against correctAnswers
blankAuto-graded — exact match against correctAnswers
open-endedMarked PENDING — requires manual review

Tests containing open-ended items will return a totalScore reflecting only the auto-graded portion until the open-ended items are reviewed.

Response

When isDone: true, the response includes the enriched item list with correctAnswers and explanation for each item, plus per-item grading results.

{
  "submissionId": "5f6a7b8c-9d0e-1f2a-3b4c-5d6e7f8a9b0c",
  "isDone": true,
  "finishedAt": "2026-03-24T11:25:42.000Z",
  "totalScore": 30,
  "maxScore": 40,
  "items": [
    {
      "sequence": 1,
      "type": "select",
      "question": "What is the solution to 2x + 3 = 11?",
      "options": ["x = 3", "x = 4", "x = 5", "x = 6"],
      "correctAnswers": ["x = 4"],
      "explanation": "Subtract 3 from both sides, then divide by 2.",
      "score": 10,
      "submittedAnswers": ["x = 4"],
      "isCorrect": true,
      "earnedScore": 10,
      "status": "GRADED"
    },
    {
      "sequence": 4,
      "type": "open-ended",
      "question": "Explain the difference between an equation and an inequality.",
      "options": null,
      "correctAnswers": null,
      "explanation": "An equation uses =, an inequality uses <, >, ≤, or ≥.",
      "score": 10,
      "submittedAnswers": ["An equation states two expressions are equal..."],
      "isCorrect": null,
      "earnedScore": null,
      "status": "PENDING"
    }
  ]
}

When isDone: false, the response simply confirms the save:

{ "submissionId": "5f6a7b8c-9d0e-1f2a-3b4c-5d6e7f8a9b0c", "isDone": false }

GET /v1/platform/tests/submissions/:submissionToken/result

Fetches the result of a finalized submission. Returns the same enriched item list as the finalize call. Returns a 4xx error if the submission is not yet isDone.

Example Request

curl https://api.tutorflow.io/v1/platform/tests/submissions/{submissionToken}/result

GET /v1/platform/tests/:id/submissions

Lists all submissions for a given test request. Requires Platform API key auth.

Example Request

curl https://api.tutorflow.io/v1/platform/tests/a1c2d3e4-.../submissions \
  -H "Authorization: Bearer tf_platform_..."

Response

FieldTypeDescription
items[].submissionIdstringSubmission ID
items[].submissionTokenstringSubmission token (for fetching result)
items[].emailstringLearner email
items[].namestring | nullLearner display name
items[].isDonebooleanWhether the submission has been finalized
items[].startedAtstringISO 8601 start timestamp
items[].finishedAtstring | nullISO 8601 finalize timestamp
items[].totalScorenumber | nullEarned score (auto-graded portion)
items[].maxScorenumber | nullMaximum possible score

Example Response

{
  "items": [
    {
      "submissionId": "5f6a7b8c-9d0e-1f2a-3b4c-5d6e7f8a9b0c",
      "submissionToken": "sub_b3f1a2c4d5e6f7890abcdef1234567890",
      "email": "alice@example.com",
      "name": "Alice",
      "isDone": true,
      "startedAt": "2026-03-24T11:00:00.000Z",
      "finishedAt": "2026-03-24T11:25:42.000Z",
      "totalScore": 30,
      "maxScore": 40
    }
  ]
}

Public Read-Only Endpoints

These additional endpoints serve the test editor preview (previewUrl):

MethodPathDescription
GET/v1/platform/tests/public/:shareTokenGet test summary (no items)
GET/v1/platform/tests/public/:shareToken/fullGet full test with items, correct answers, and explanations
GET/v1/platform/tests/public/:shareToken/items/:sequenceGet a single item with answer

/full and /items/:sequence automatically refresh the underlying edit token if it has expired, so editor previews always work without manual token refresh.