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.
| Unit | Price |
|---|---|
| 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
tierfield: still accepted (fast/standard/advanced) for backwards compatibility but has no effect on price. Omit it in new integrations. Thedefaulttier appears only in responsepriceSnapshotand the pricing catalog.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
evaluationType | string | Yes | open_ended, rubric_short_answer, or exact |
questionText | string | Yes | The question being evaluated |
learnerAnswer | string | Yes | The student's answer |
tier | string | No | Legacy request value only: fast, standard, or advanced. Omit for new integrations. Do not send default; default is a response/catalog tier. |
language | string | No | Language for feedback (default: en). Applies to AI-backed open-ended and rubric evaluations; exact-match evaluation returns fixed English feedback |
maxScore | number | No | Maximum score (default: 10) |
referenceAnswer | string | No | Expected answer. Always send this for exact; if omitted, the current matcher compares against an empty string |
rubric | object | No | Rubric criteria object for rubric_short_answer. If omitted, TutorFlow still evaluates with an empty criteria list |
subject | string | No | Subject area for evaluation context (e.g., math, science) |
gradeLevel | string | No | Grade or education level of the learner (e.g., grade-10, university) |
difficulty | string | No | Difficulty level of the question (e.g., easy, medium, hard) |
submitter | object | No | Structured learner identity. { learnerId: string, learnerName?: string }. Takes precedence over learnerExternalId. See Learner Tracking |
learnerExternalId | string | No | Legacy learner identifier. Use submitter.learnerId instead |
conceptTags | string[] | No | Tags for the concepts being evaluated (e.g., ["algebra", "quadratic-equations"]). Required for mastery tracking |
rubricCriteria | object[] | No | Structured rubric criteria as an array of { name, description, maxScore } objects. Alternative to the rubric object |
feedbackOptions | object | No | Feedback formatting preferences. Supports tone (e.g., encouraging, neutral) and detailLevel (e.g., brief, detailed) |
clientMetadata | object | No | Optional integration metadata stored with the evaluation. For LTI correlation, pass { "ltiLaunchSessionId": "..." }; this does not enqueue grade sync by itself. |
processingMode | string | No | Processing mode override |
idempotencyKey | string | No | Prevents duplicate processing. Can also be sent via Idempotency-Key HTTP header |
mode | string | No | sync (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
| Field | Type | Description |
|---|---|---|
id | string | Evaluation request ID |
status | string | PENDING, PROCESSING, COMPLETED, or FAILED |
evaluationType | string | The evaluation type used |
idempotencyKey | string | null | The idempotency key if provided |
idempotentReplay | boolean | true if this response reused an existing evaluation |
mode | string | sync or async |
tier | string | The tier applied |
priceSnapshot | object | Pricing details at time of request |
score | number | null | Achieved score (null if not yet complete) |
maxScore | number | Maximum possible score |
normalizedScore | number | null | Score normalized to 0–100 scale |
confidence | number | null | Confidence in the evaluation (0–1). Exact-match returns 1 |
rubricBreakdown | object[] | null | Per-criterion scores (rubric type only). Each item has criterion, score, maxScore, feedback |
strengths | string[] | Identified strengths in the answer |
mistakes | string[] | Identified mistakes or weaknesses |
suggestions | string[] | Improvement suggestions |
feedbackSummary | string | null | Overall feedback narrative |
nextStep | string | null | Recommended next learning step |
rubricFiles | object[] | Uploaded rubric files. Each item has url, fileName, mimeType, size |
answerFiles | object[] | Uploaded answer files. Each item has url, fileName, mimeType, size |
isTerminal | boolean | Whether the evaluation is in a final state |
pollAfterMs | number | null | Suggested polling interval in ms (async mode) |
createdAt | string | ISO 8601 timestamp |
completedAt | string | null | ISO 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.