LTI Grade Sync

Automatic grade passback to LMS gradebooks using LTI Assignment and Grade Services (AGS).

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 implements AGS to automatically sync evaluation scores when a student completes an LTI-launched assessment.

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

{
  "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 student launches TutorFlow from an LMS assignment and completes an evaluation, the following happens automatically:

1. Student launches TutorFlow via LTI
   -> TutorFlow stores AGS endpoint and credentials in the launch session
 
2. Student submits answer, evaluation runs
   -> Evaluation completes with a score
 
3. TutorFlow requests an OAuth2 access token from the LMS
   POST {platformTokenEndpoint}
   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 automatically after the evaluation completes. No additional API calls are needed from your side.

Triggering Grade Sync from the REST API

If you are building a custom integration where evaluations are created via the REST API (rather than through the LTI UI), you can link an evaluation to an LTI launch session. This allows the automatic grade sync to work even when the evaluation is created programmatically.

Include the ltiLaunchSessionId in the clientMetadata field of your evaluation 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 concept of supply and demand",
    "learnerAnswer": "Supply and demand is the relationship between...",
    "language": "en",
    "maxScore": 10,
    "clientMetadata": {
      "ltiLaunchSessionId": "session_abc123"
    }
  }'

When the evaluation completes, TutorFlow looks up the launch session, retrieves the AGS credentials, and posts the score to the LMS.

Where to Get the Launch Session ID

The ltiLaunchSessionId is returned in the launch session context when TutorFlow processes an LTI launch. If you are building a custom frontend that embeds inside the LMS iframe, the session ID is available in the launch response and can be passed to your backend for use in evaluation requests.

Score Format

TutorFlow posts scores using the AGS Score service format:

{
  "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 the student received (from the evaluation result)
scoreMaximumnumberThe maximum possible score (from the evaluation maxScore)
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
FullyGradedEvaluation completed successfully
PendingEvaluation is still processing
PendingManualRequires manual review (not currently used)
FailedEvaluation failed (score not posted to LMS)
NotReadyNot yet ready for grading

Score Mapping

TutorFlow maps evaluation results to AGS scores as follows:

Evaluation FieldAGS Field
scorescoreGiven
maxScorescoreMaximum
Status COMPLETEDactivityProgress: Completed, gradingProgress: FullyGraded
Status FAILEDGrade sync is skipped (no score posted)
Status PENDING / PROCESSINGGrade sync waits until the evaluation reaches a terminal state

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 retry30 seconds
3rd retry120 seconds

After 3 retries, the sync is marked as failed. The evaluation itself remains in the COMPLETED state. You can check whether the grade sync succeeded by looking at the evaluation's ltiGradeSyncStatus field:

curl https://api.tutorflow.io/v1/platform/evaluations/2f4ad455-1e8e-4b6c-9f3a-7ebf4cf6f483 \
  -H "Authorization: Bearer tf_platform_..."
{
  "id": "2f4ad455-1e8e-4b6c-9f3a-7ebf4cf6f483",
  "status": "COMPLETED",
  "score": 8,
  "maxScore": 10,
  "ltiGradeSyncStatus": "synced",
  "ltiGradeSyncedAt": "2026-03-25T12:05:01Z"
}

Grade Sync Status Values

StatusDescription
pendingGrade sync has not yet been attempted
syncingCurrently posting the score to the LMS
syncedScore successfully posted to the LMS gradebook
failedAll retry attempts exhausted
not_applicableEvaluation was not linked to an LTI launch session

Webhook Events

When grade sync completes or fails, TutorFlow emits webhook events if you have Webhooks configured:

EventDescription
lti.grade_syncedScore successfully posted to LMS
lti.grade_sync_failedGrade sync failed after all retries

Example Webhook Payload

{
  "event": "lti.grade_synced",
  "evaluationId": "2f4ad455-1e8e-4b6c-9f3a-7ebf4cf6f483",
  "ltiRegistrationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "scoreGiven": 8.0,
  "scoreMaximum": 10.0,
  "userId": "lti-user-sub-claim",
  "syncedAt": "2026-03-25T12:05:01Z"
}