LTI Grade Sync

How TutorFlow's LTI grade-sync job posts a score to an LMS gradebook over AGS, and why no API call queues one now.

Use this page to see how TutorFlow's grade-sync job posts a score to an LMS gradebook.

No API route queues a grade sync now. Evaluations on the Content API do not send scores to the LMS, and the Platform routes and test page that did were removed on 2026-10-16 (they answer 410 platform_route_removed). See Triggering Grade Sync from the API. Classroom tests that learners take through an LTI launch still post their scores this way, with no API call. The rest of this page describes the job itself.

Grade Sync via AGS

The Assignment and Grade Services (AGS) specification is the LTI 1.3 standard for sending scores from a tool back to the LMS gradebook. TutorFlow's grade-sync job uses AGS to post a score for one LTI launch session, when something queues that job.

How AGS Works

AGS defines a REST API that the LMS exposes for managing line items (grade columns) and posting scores. During an LTI launch, the LMS includes an AGS claim in the JWT that provides the endpoint URLs and scopes available to TutorFlow.

AGS Claim in the Launch Token

JSON
{
  "https://purl.imsglobal.org/spec/lti-ags/claim/endpoint": {
    "scope": [
      "https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
      "https://purl.imsglobal.org/spec/lti-ags/scope/score",
      "https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly"
    ],
    "lineitems": "https://canvas.instructure.com/api/lti/courses/1/line_items",
    "lineitem": "https://canvas.instructure.com/api/lti/courses/1/line_items/42"
  }
}
FieldDescription
scopeThe AGS operations TutorFlow is authorized to perform
lineitemsURL to manage all line items for the course (optional)
lineitemURL for the specific line item linked to this assignment

Score Sync Flow

When a grade-sync job runs for an LTI launch session, the following happens:

1. Student launches TutorFlow via LTI
   -> TutorFlow stores AGS endpoint and credentials in the launch session
 
2. Something queues platform-lti-grade-sync for that launch session
   (until 2026-10-16: a finished test on the removed Platform test page)
   -> The job payload carries the score and the launch session reference
 
3. TutorFlow requests an OAuth2 access token from the LMS
   POST {tokenEndpoint}
   grant_type=client_credentials
   scope=https://purl.imsglobal.org/spec/lti-ags/scope/score
 
4. TutorFlow posts the score to the LMS line item
   POST {lineitem}/scores
   Authorization: Bearer {access_token}
 
5. LMS updates the gradebook

TutorFlow handles steps 3 through 5 inside the grade-sync job.

Triggering Grade Sync from the API

No API route queues an LTI grade sync now. The route that did, POST /v1/platform/evaluations with clientMetadata.ltiLaunchSessionId, was removed on 2026-10-16 with the other Platform content routes; see Migrating to the Content API.

Evaluations made on the Content API, POST /v1/content/classrooms/{classroomId}/evaluations, store clientMetadata for your own correlation but do not queue an LTI grade sync:

bash
curl -X POST "https://api.tutorflow.io/v1/content/classrooms/$CLASSROOM_ID/evaluations" \
  -H "Authorization: Bearer tf_content_..." \
  -H "Content-Type: application/json" \
  -d '{
    "evaluationType": "open_ended",
    "questionText": "Explain the concept of supply and demand",
    "learnerAnswer": "Supply and demand is the relationship between...",
    "language": "en",
    "maxScore": 10,
    "clientMetadata": {
      "ltiLaunchSessionId": "3f0f9f52-7a1b-4b6e-9a53-2b8f6f1a2c3d"
    }
  }'

Automatic Triggers

Tests made on the removed /v1/platform test routes used to sync their score when a learner finished them on the Platform test-taking page. That page was removed on 2026-10-16: an LTI launch of such a test now opens the test's classroom page, and no score is sent back to the LMS. Grade passback through TutorFlow is not available for them now.

Where to Get the Launch Session ID

After a successful launch, TutorFlow redirects the browser to:

{frontend}/platform/lti/launch?sessionId={sessionId}

The launch page forwards the id to the target content as the ltiSessionId query parameter. Read it there if you need to correlate REST-created evaluations with the LTI session.

Score Format

TutorFlow posts scores using the AGS Score service format:

JSON
{
  "scoreGiven": 8.0,
  "scoreMaximum": 10.0,
  "activityProgress": "Completed",
  "gradingProgress": "FullyGraded",
  "userId": "lti-user-sub-claim",
  "timestamp": "2026-03-25T12:05:00Z"
}

Score Fields

FieldTypeDescription
scoreGivennumberThe score from the grade-sync job payload (required: jobs without a score fail instead of posting 0)
scoreMaximumnumberThe maximum score from the grade-sync job payload (required, must be greater than 0)
activityProgressstringThe student's progress on the activity
gradingProgressstringThe grading status
userIdstringThe sub claim from the LTI launch token (identifies the student in the LMS)
timestampstringISO 8601 timestamp of when the score was recorded

Activity Progress Values

ValueWhen Used
InitializedLaunch started but no submission yet
StartedStudent has begun the activity
InProgressStudent is working on the activity
SubmittedStudent submitted but grading is pending
CompletedActivity and grading are both finished

Grading Progress Values

ValueWhen Used
FullyGradedAll items were auto-graded (or the evaluation completed)
PendingEvaluation is still processing
PendingManualThe test contains open-ended items that require manual review
FailedEvaluation failed (score not posted to LMS)
NotReadyNot yet ready for grading

Score Mapping

TutorFlow maps the grade-sync job payload to AGS scores as follows:

Job payloadAGS Field
score (required)scoreGiven
maxScore (required)scoreMaximum
Auto-graded test / completed evaluationactivityProgress: Completed, gradingProgress: FullyGraded
Test with open-ended itemsactivityProgress: Completed, gradingProgress: PendingManual
Job failureScore is not posted after retries are exhausted

Error Handling

If the grade sync fails (e.g., the LMS token endpoint is unreachable or the line item URL has expired), TutorFlow retries with exponential backoff:

AttemptDelay
1st retry5 seconds
2nd retry25 seconds

After the initial attempt plus 2 retries (3 total attempts), the sync is marked as failed. The test result itself is kept. To check whether the grade sync succeeded, look at the LMS gradebook.

Webhook Events

TutorFlow used to send lti.grade_synced and lti.grade_sync_failed to Agent Platform webhook endpoints. Those endpoints were removed on 2026-10-16, and LTI event delivery is not available through the API for now. See Webhooks.