Create Evaluation

Submit a student answer for grading and receive structured feedback.

POST /v1/platform/evaluations

Creates an evaluation request. TutorFlow grades the learner's answer and returns structured feedback including score, strengths, and improvement suggestions. Open-ended and rubric-based requests use AI evaluation. Exact-match requests use a deterministic local matcher.

Pricing

Evaluations are billed per request at a single flat rate, regardless of evaluationType, answer length, or rubric complexity.

UnitPrice
Per evaluation request$0.02

The priceSnapshot returned with the evaluation response carries the full billing record:

{
  "category": "evaluation",
  "tier": "default",
  "unit": "request",
  "unitPrice": 0.02,
  "units": 1,
  "amountUsd": 0.02,
  "currency": "USD",
  "source": "platform_pricing_catalog_v2"
}

Legacy tier field: still accepted (fast / standard / advanced) for backwards compatibility but has no effect on price. Omit it in new integrations. The default tier appears only in response priceSnapshot and the pricing catalog.

Request Body

FieldTypeRequiredDescription
evaluationTypestringYesopen_ended, rubric_short_answer, or exact
questionTextstringYesThe question being evaluated
learnerAnswerstringYesThe student's answer
tierstringNoLegacy request value only: fast, standard, or advanced. Omit for new integrations. Do not send default; default is a response/catalog tier.
languagestringNoLanguage for feedback (default: en). Applies to AI-backed open-ended and rubric evaluations; exact-match evaluation returns fixed English feedback
maxScorenumberNoMaximum score (default: 10)
referenceAnswerstringNoExpected answer. Always send this for exact; if omitted, the current matcher compares against an empty string
rubricobjectNoRubric criteria object for rubric_short_answer. If omitted, TutorFlow still evaluates with an empty criteria list
subjectstringNoSubject area for evaluation context (e.g., math, science)
gradeLevelstringNoGrade or education level of the learner (e.g., grade-10, university)
difficultystringNoDifficulty level of the question (e.g., easy, medium, hard)
submitterobjectNoStructured learner identity. { learnerId: string, learnerName?: string }. Takes precedence over learnerExternalId. See Learner Tracking
learnerExternalIdstringNoLegacy learner identifier. Use submitter.learnerId instead
conceptTagsstring[]NoTags for the concepts being evaluated (e.g., ["algebra", "quadratic-equations"]). Required for mastery tracking
rubricCriteriaobject[]NoStructured rubric criteria as an array of { name, description, maxScore } objects. Alternative to the rubric object
feedbackOptionsobjectNoFeedback formatting preferences. Supports tone (e.g., encouraging, neutral) and detailLevel (e.g., brief, detailed)
clientMetadataobjectNoOptional integration metadata stored with the evaluation. For LTI correlation, pass { "ltiLaunchSessionId": "..." }; this does not enqueue grade sync by itself.
processingModestringNoProcessing mode override
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/evaluations \
  -H "Authorization: Bearer tf_platform_..." \
  -H "Content-Type: application/json" \
  -d '{
    "evaluationType": "open_ended",
    "questionText": "Explain the water cycle",
    "learnerAnswer": "Water evaporates from oceans...",
    "language": "en",
    "maxScore": 10
  }'

Response Fields

FieldTypeDescription
idstringEvaluation request ID
statusstringPENDING, PROCESSING, COMPLETED, or FAILED
evaluationTypestringThe evaluation type used
idempotencyKeystring | nullThe idempotency key if provided
idempotentReplaybooleantrue if this response reused an existing evaluation
modestringsync or async
tierstringThe tier applied
priceSnapshotobjectPricing details at time of request
scorenumber | nullAchieved score (null if not yet complete)
maxScorenumberMaximum possible score
normalizedScorenumber | nullScore normalized to 0–100 scale
confidencenumber | nullConfidence in the evaluation (0–1). Exact-match returns 1
rubricBreakdownobject[] | nullPer-criterion scores (rubric type only). Each item has criterion, score, maxScore, feedback
strengthsstring[]Identified strengths in the answer
mistakesstring[]Identified mistakes or weaknesses
suggestionsstring[]Improvement suggestions
feedbackSummarystring | nullOverall feedback narrative
nextStepstring | nullRecommended next learning step
rubricFilesobject[]Uploaded rubric files. Each item has url, fileName, mimeType, size
answerFilesobject[]Uploaded answer files. Each item has url, fileName, mimeType, size
isTerminalbooleanWhether the evaluation is in a final state
pollAfterMsnumber | nullSuggested polling interval in ms (async mode)
createdAtstringISO 8601 timestamp
completedAtstring | nullISO 8601 timestamp (null if not complete)

Example Response

{
  "id": "2f4ad455-1e8e-4b6c-9f3a-7ebf4cf6f483",
  "status": "COMPLETED",
  "evaluationType": "open_ended",
  "idempotencyKey": null,
  "idempotentReplay": false,
  "mode": "sync",
  "tier": "default",
  "priceSnapshot": {
    "category": "evaluation",
    "catalogKey": "evaluation.default",
    "tier": "default",
    "unit": "request",
    "unitPrice": 0.02,
    "units": 1,
    "amountUsd": 0.02,
    "currency": "USD",
    "source": "platform_pricing_catalog_v2"
  },
  "score": 8,
  "maxScore": 10,
  "normalizedScore": 80,
  "confidence": 0.92,
  "strengths": [
    "Correctly identifies evaporation as a key process",
    "Good use of scientific terminology"
  ],
  "mistakes": [
    "Did not mention condensation"
  ],
  "suggestions": [
    "Include condensation as a step",
    "Mention the role of transpiration from plants"
  ],
  "rubricBreakdown": null,
  "feedbackSummary": "Strong understanding of the water cycle with clear explanation of evaporation and precipitation.",
  "nextStep": "Study the condensation and precipitation phases to complete your understanding.",
  "rubricFiles": [],
  "answerFiles": [],
  "isTerminal": true,
  "createdAt": "2026-03-19T10:30:00Z",
  "completedAt": "2026-03-19T10:30:01Z"
}

Async Mode

Set "mode": "async" to queue the evaluation for background processing. This is useful for long-running evaluations or when you don't need the result immediately.

curl -X POST https://api.tutorflow.io/v1/platform/evaluations \
  -H "Authorization: Bearer tf_platform_..." \
  -H "Content-Type: application/json" \
  -d '{
    "evaluationType": "open_ended",
    "questionText": "Write an essay about climate change",
    "learnerAnswer": "Climate change is...",
    "mode": "async"
  }'

The response returns immediately with "status": "PENDING" and a pollAfterMs value:

{
  "id": "2f4ad455-1e8e-4b6c-9f3a-7ebf4cf6f483",
  "status": "PENDING",
  "evaluationType": "open_ended",
  "isTerminal": false,
  "pollAfterMs": 1000
}

Use the Get Evaluation endpoint to poll for results, or configure Webhooks to receive evaluation.completed or evaluation.failed events.

Idempotency

Pass an idempotencyKey in the request body or Idempotency-Key header to prevent duplicate evaluations. If the same key is sent again, the original result is returned without re-processing.

curl -X POST https://api.tutorflow.io/v1/platform/evaluations \
  -H "Authorization: Bearer tf_platform_..." \
  -H "Idempotency-Key: my-unique-request-123" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

The body field idempotencyKey takes precedence over the header if both are provided.

File Attachments

Use multipart/form-data to include file attachments (max 10 files per field):

curl -X POST https://api.tutorflow.io/v1/platform/evaluations \
  -H "Authorization: Bearer tf_platform_..." \
  -F "evaluationType=rubric_short_answer" \
  -F "questionText=Analyze this data set" \
  -F "learnerAnswer=Based on the data..." \
  -F 'rubric={"criteria":[{"name":"Accuracy","description":"Correct interpretation","maxScore":5}]}' \
  -F "rubricFiles=@rubric.pdf" \
  -F "answerFiles=@student_work.pdf"

See Pricing and Billing for the full per-unit pricing model.