Learner Tracking

Track scores and mastery progress per learner across evaluations. Submit a submitter object to identify learners, then query per-learner statistics and per-concept mastery through the Learners API.

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:

  1. The learner record is created or updated. A PlatformLearner row is upserted for submitter.learnerId. If the learner does not yet exist, it is created with the provided display name.
  2. 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

FieldTypeRequiredDescription
submitter.learnerIdstringYesYour system's identifier for this learner. Stable across evaluations.
submitter.learnerNamestringNoHuman-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) × 100

For 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:

EvaluationScoremasteryScore after
1st7070
2nd90(70×1 + 90) / 2 = 80
3rd50(80×2 + 50) / 3 = 70

status: mastery level

masteryScore is mapped to one of three statuses:

StatusRangeMeaning
NEEDS_REMEDIATION0–59The learner has not yet grasped this concept. Review or re-teach recommended.
DEVELOPING60–84Basic understanding is present. Further practice will consolidate the concept.
MASTERED85–100The learner has demonstrated reliable command of this concept.

List Learners

Returns all learners seen in the workspace, with aggregate evaluation statistics.

GET /v1/platform/learners

Query Parameters

ParameterTypeDefaultDescription
limitnumber20Items per page (1–100)
offsetnumber0Number 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

FieldTypeDescription
itemsarrayList of learner records
totalnumberTotal number of learners in this workspace
learnerIdstringYour system's identifier for this learner
learnerNamestring | nullDisplay name, if provided
totalEvaluationsnumberNumber of completed evaluations for this learner
avgNormalizedScorenumber | nullAverage normalized score (0–100) across all completed evaluations
createdAtstringISO 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/:learnerId

Example 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

FieldTypeDescription
learnerIdstringYour system's identifier for this learner
learnerNamestring | nullDisplay name, if provided
totalEvaluationsnumberTotal completed evaluations
avgNormalizedScorenumber | nullAverage normalized score across all completed evaluations
masterySummariesarrayPer-concept mastery records

Each item in masterySummaries:

FieldTypeDescription
conceptKeystringNormalized concept identifier (lowercase, hyphenated)
conceptTitlestringOriginal tag text as provided
statusstringNEEDS_REMEDIATION, DEVELOPING, or MASTERED
masteryScorenumber | nullCumulative weighted average score (0–100)
signalCountnumberNumber of evaluations that contributed to this mastery record
lastEvaluatedAtstring | nullISO 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:

  1. Include submitter in every evaluation. Use a stable identifier from your system (user ID, session ID, etc.).
  2. Tag concepts you are testing. Pass conceptTags that correspond to the learning objectives being assessed.
  3. Query the learner profile after each session. GET /v1/platform/learners/:learnerId returns masterySummaries you can use to decide which concepts need more practice.
  4. Use NEEDS_REMEDIATION as a re-teach signal. If status is NEEDS_REMEDIATION after two or more signals, the learner needs a different explanation or additional worked examples.
  5. Use MASTERED as a progression signal. Move to the next concept or increase difficulty when status reaches MASTERED.
# 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_..."