Overview
Learner tracking connects individual evaluations to a learner identity so you can see how each student is progressing over time.
Two things happen automatically when you include a submitter in an evaluation request:
- The learner record is created or updated. A
PlatformLearnerrow is upserted forsubmitter.learnerId. If the learner does not yet exist, it is created with the provided display name. - Mastery signals are recorded. If the request also includes
conceptTags, TutorFlow records a learning signal per concept and recalculates the learner's mastery score for that concept.
Submitting Learner Identity
Add a submitter object to any Create Evaluation request.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
submitter.learnerId | string | Yes | Your system's identifier for this learner. Stable across evaluations. |
submitter.learnerName | string | No | Human-readable display name. Persisted on first encounter; ignored on subsequent calls if a name is already stored. |
submitter.learnerId is equivalent to the legacy learnerExternalId field. If both are provided, submitter takes precedence.
Example
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 photosynthesis",
"learnerAnswer": "Plants use sunlight to convert CO2 and water into glucose.",
"language": "en",
"submitter": {
"learnerId": "learner_9c4d2e1f",
"learnerName": "Alex Kim"
}
}'Concept Mastery Tracking
To track mastery on specific concepts, add conceptTags to the evaluation request alongside submitter.
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 photosynthesis",
"learnerAnswer": "Plants use sunlight and chlorophyll to convert CO2 and water into glucose and oxygen.",
"language": "en",
"conceptTags": ["photosynthesis", "biology"],
"submitter": {
"learnerId": "learner_9c4d2e1f",
"learnerName": "Alex Kim"
}
}'Each tag in conceptTags is tracked independently. A learner can have separate mastery scores for "photosynthesis" and "biology" even if both appear in the same evaluation.
If conceptTags is omitted, the learner record is still created, but no mastery data is recorded.
How masteryScore is Calculated
Each time an evaluation with conceptTags completes, TutorFlow records a learning signal for every tag and updates the learner's mastery score for each concept.
normalizedScore
The AI grades the answer and returns a normalizedScore on a 0–100 scale:
normalizedScore = (score / maxScore) × 100For example, a score of 7 out of 10 gives a normalizedScore of 70.
masteryScore: cumulative weighted average
Rather than replacing the previous score, each new signal is blended into a running average weighted by the number of prior signals. One strong performance does not immediately jump the mastery score, and one weak performance does not collapse it.
masteryScore = (previousMasteryScore × priorSignalCount + newNormalizedScore) / (priorSignalCount + 1)Example progression for the "photosynthesis" concept:
| Evaluation | Score | masteryScore after |
|---|---|---|
| 1st | 70 | 70 |
| 2nd | 90 | (70×1 + 90) / 2 = 80 |
| 3rd | 50 | (80×2 + 50) / 3 = 70 |
status: mastery level
masteryScore is mapped to one of three statuses:
| Status | Range | Meaning |
|---|---|---|
NEEDS_REMEDIATION | 0–59 | The learner has not yet grasped this concept. Review or re-teach recommended. |
DEVELOPING | 60–84 | Basic understanding is present. Further practice will consolidate the concept. |
MASTERED | 85–100 | The learner has demonstrated reliable command of this concept. |
List Learners
Returns all learners seen in the workspace, with aggregate evaluation statistics.
GET /v1/platform/learnersQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Items per page (1–100) |
offset | number | 0 | Number of items to skip |
Example Request
curl "https://api.tutorflow.io/v1/platform/learners" \
-H "Authorization: Bearer tf_platform_..."Response
{
"items": [
{
"learnerId": "learner_9c4d2e1f",
"learnerName": "Alex Kim",
"totalEvaluations": 3,
"avgNormalizedScore": 76.7,
"createdAt": "2026-04-09T12:10:12.004Z"
},
{
"learnerId": "learner_legacy_001",
"learnerName": null,
"totalEvaluations": 1,
"avgNormalizedScore": 100,
"createdAt": "2026-04-09T12:10:38.398Z"
}
],
"total": 2
}Response Fields
| Field | Type | Description |
|---|---|---|
items | array | List of learner records |
total | number | Total number of learners in this workspace |
learnerId | string | Your system's identifier for this learner |
learnerName | string | null | Display name, if provided |
totalEvaluations | number | Number of completed evaluations for this learner |
avgNormalizedScore | number | null | Average normalized score (0–100) across all completed evaluations |
createdAt | string | ISO 8601 timestamp of first evaluation |
Get Learner Profile
Returns the full profile for a single learner, including per-concept mastery summaries.
GET /v1/platform/learners/:learnerIdExample Request
curl "https://api.tutorflow.io/v1/platform/learners/learner_9c4d2e1f" \
-H "Authorization: Bearer tf_platform_..."Response
{
"learnerId": "learner_9c4d2e1f",
"learnerName": "Alex Kim",
"totalEvaluations": 3,
"avgNormalizedScore": 76.7,
"masterySummaries": [
{
"conceptKey": "photosynthesis",
"conceptTitle": "photosynthesis",
"status": "DEVELOPING",
"masteryScore": 70,
"signalCount": 2,
"lastEvaluatedAt": "2026-04-09T12:13:18.442Z"
},
{
"conceptKey": "biology",
"conceptTitle": "biology",
"status": "DEVELOPING",
"masteryScore": 70,
"signalCount": 1,
"lastEvaluatedAt": "2026-04-09T12:13:19.310Z"
}
]
}Response Fields
| Field | Type | Description |
|---|---|---|
learnerId | string | Your system's identifier for this learner |
learnerName | string | null | Display name, if provided |
totalEvaluations | number | Total completed evaluations |
avgNormalizedScore | number | null | Average normalized score across all completed evaluations |
masterySummaries | array | Per-concept mastery records |
Each item in masterySummaries:
| Field | Type | Description |
|---|---|---|
conceptKey | string | Normalized concept identifier (lowercase, hyphenated) |
conceptTitle | string | Original tag text as provided |
status | string | NEEDS_REMEDIATION, DEVELOPING, or MASTERED |
masteryScore | number | null | Cumulative weighted average score (0–100) |
signalCount | number | Number of evaluations that contributed to this mastery record |
lastEvaluatedAt | string | null | ISO 8601 timestamp of the most recent signal |
Filter Evaluations by Learner
Use the learnerId query parameter on the List Evaluations endpoint to retrieve only evaluations belonging to a specific learner.
curl "https://api.tutorflow.io/v1/platform/evaluations?learnerId=learner_9c4d2e1f" \
-H "Authorization: Bearer tf_platform_..."This filter can be combined with status, evaluationType, limit, and offset.
For AI Agents
If you are an autonomous agent integrating with TutorFlow, use this pattern to build a learner model over time:
- Include
submitterin every evaluation. Use a stable identifier from your system (user ID, session ID, etc.). - Tag concepts you are testing. Pass
conceptTagsthat correspond to the learning objectives being assessed. - Query the learner profile after each session.
GET /v1/platform/learners/:learnerIdreturnsmasterySummariesyou can use to decide which concepts need more practice. - Use
NEEDS_REMEDIATIONas a re-teach signal. IfstatusisNEEDS_REMEDIATIONafter two or more signals, the learner needs a different explanation or additional worked examples. - Use
MASTEREDas a progression signal. Move to the next concept or increase difficulty whenstatusreachesMASTERED.
# Step 1: Run evaluation
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": "What is the role of chlorophyll in photosynthesis?",
"learnerAnswer": "Chlorophyll absorbs light energy to drive the light reactions.",
"language": "en",
"conceptTags": ["photosynthesis", "chlorophyll"],
"submitter": {
"learnerId": "learner_9c4d2e1f",
"learnerName": "Alex Kim"
}
}'
# Step 2: Check mastery after session
curl "https://api.tutorflow.io/v1/platform/learners/learner_9c4d2e1f" \
-H "Authorization: Bearer tf_platform_..."