How LTI® Grade Passback Works
The short answer
Grade passback is Assignment and Grade Services, one of the LTI® Advantage services. Your tool posts a score against a line item — a column in the LMS gradebook — and the LMS records it against that user. Three concepts do all the work: line items, scores and results.
It is specified as Assignment and Grade Services 2.0 by 1EdTech Consortium, Inc.
The three concepts
A line item is a gradebook column. In most integrations one already exists: the LMS created it when the activity was added to the course. You can also create your own, which is what you want if a single activity produces several marks.
A score is a submission for one user. Posting one does not replace the column; it records a result within it.
A result is what the gradebook currently holds. Read-only, and the honest answer to "did that actually land".
Getting permission
Service calls are not authorised by the launch. Verifying a launch proves who the user is; it grants nothing.
To call a service, your tool signs an assertion with its own private key, exchanges it at the platform's token endpoint for an access token scoped to specific permissions, and calls the service with that. Four scopes matter here:
| Scope | Allows |
|---|---|
.../lti-ags/scope/lineitem | Create, update and delete columns |
.../lti-ags/scope/lineitem.readonly | List and read columns |
.../lti-ags/scope/score | Post scores |
.../lti-ags/scope/result.readonly | Read what the gradebook holds |
Scopes are granted per registration and per course, so a tool can have grade access in one course and not another. Treat a missing service as normal rather than as an error — the launch tells you which services are available for that context, and branching on that is more reliable than assuming.
Posting a score
{
"userId": "9a8b7c6d",
"scoreGiven": 95,
"scoreMaximum": 100,
"activityProgress": "Completed",
"gradingProgress": "FullyGraded",
"timestamp": "2026-08-11T10:04:00Z"
}
The two progress fields are more important than they look, because the LMS decides what to display based on them, not on the score.
activityProgress describes what the learner did — Initialized, Started,
InProgress, Submitted, Completed.
gradingProgress describes whether the mark is final — NotReady, Failed,
Pending, PendingManual, FullyGraded.
Only FullyGraded means "show this". A score sent with Pending is accepted,
stored, and not displayed — which is the single most common reason for "the API
returned success and the teacher sees nothing".
scoreGiven is optional. Omitting it while sending progress fields is how you
record that someone started or submitted without assigning a mark.
Why a score does not appear
In the order worth checking:
gradingProgress is not FullyGraded. Above.
You posted to a different line item than the one on screen. If your tool created a column, that is not the column the LMS created for the activity. Read the line items back and look at what exists.
The column is read-only. Some platforms lock columns under certain configurations, and the LMS rejects the write with its own error. A good client surfaces that error rather than flattening it into a 500.
The user identifier is wrong. userId is the sub from the launch for that
platform, not your internal ID and not an email address.
A 401 with insufficient scope. The registration was not granted the score scope. That is an administrator change, not a code change.
Grading after the launch
Most real grading is asynchronous — a human marks an essay on Thursday, a job runs overnight. By then the browser session is long gone.
This needs credentials that outlive the launch. With LTIAAS that is the service key, issued alongside the launch data when grade services are available. It does not expire with the session and it carries the service endpoints for that context, so a background job can post a score days later without a live launch.
The asynchronous grading guide covers the pattern.
What LTIAAS handles
The token exchange, the assertion signing and the endpoint discovery, so a score post is one authenticated request:
await axios.post(
`https://your.ltiaas.com/api/lineitems/${lineItemId}/scores`,
{ userId, scoreGiven: 95, scoreMaximum: 100,
activityProgress: 'Completed', gradingProgress: 'FullyGraded' },
{ headers: { Authorization: `LTIK-AUTH-V2 ${API_KEY}:${ltik}` } }
)
Some conveniences worth knowing about, because they remove failures rather than
just typing. scoreMaximum is filled in from the line item if you send only
scoreGiven. The timestamp is stamped for you. Both progress fields are validated
against the permitted vocabularies before the call leaves, so a typo fails
immediately with a clear message rather than being rejected by the LMS. And where
a platform sends only a single line item endpoint rather than a container, LTIAAS
falls back to it instead of failing.
When the LMS does reject something, its status code, the URL called and both bodies are surfaced — which is the difference between "the column is read-only" and "500".
Common questions
What is LTI® grade passback?
Sending a score from your tool back into the LMS gradebook, using Assignment and Grade Services. Your tool posts a score against a line item — a gradebook column — and the LMS records it for that user.
What is a line item?
A column in the gradebook. It usually already exists, created by the LMS when the activity was added to the course. Your tool can also create its own if it needs more than one column per activity.
Why does my score return success but not appear in the gradebook?
Usually the column. The score was accepted against a line item that is not the one on screen, or gradingProgress was not FullyGraded so the LMS is holding it as pending. Read the results back to see what the gradebook actually holds.
Can I send a grade after the launch has ended?
Yes, and it is the normal case for anything graded asynchronously. It needs credentials that outlive the launch — with LTIAAS that is the service key, which does not expire with the session.
Next
- How LTI® roster access works
- Asynchronous grading — grading after the launch
- Grade passback guide — the LTIAAS walkthrough
