Skip to main content
Version: 2026-08-25 (archived)

Grades API reference

Base URL: https://api.link.voshi.com/ltiaas/v1

All grade endpoints authenticate with your API key:

Authorization: Bearer ltiaas_<app-id>_<secret>

Submit a grade​

POST /ltiaas/v1/grades
Content-Type: application/json

Creates the grade for a launch, or — if one already exists for that launch_id — updates it and re-syncs. See one grade per launch.

Request body​

launch_idstringrequired

The launch to grade, from the launch JWT's launch_id claim. The launch must belong to your app and must have arrived with grade_passback: true.

scorenumberrequired

The score as a fraction from 0.0 to 1.0.

max_scorenumber

Optional. The points the gradebook column should be worth. Sending it updates the LMS gradebook column to this value before the score is published, so 0.85 renders as 42.5 out of a max_score of 50. Must be greater than 0. Omit it to leave the column at whatever the instructor (or your points declaration) set.

warning

Sending max_score requires the school's LMS developer key to grant the AGS line item scope on top of the score scope. On a deployment that only grants score, a grade carrying max_score fails to sync — loudly, in sync_error — rather than silently mis-scaling. If you don't need to change the column's value, don't send the field.

commentstringdefault:

A comment shown to the student alongside the grade.

activity_progressstringdefault: Completed

Completed or Submitted — whether the student has finished the activity.

grading_progressstringdefault: FullyGraded

FullyGraded or Pending — whether this score is final.

Example​

curl -X POST "https://api.link.voshi.com/ltiaas/v1/grades" \
-H "Authorization: Bearer ltiaas_myappid_mysecret" \
-H "Content-Type: application/json" \
-d '{
"launch_id": "I9gbX9ExUrt6",
"score": 0.85,
"comment": "Nice work!"
}'

Response — 200​

{
"grade_id": "Gr8dEx",
"launch_id": "I9gbX9ExUrt6",
"score": 0.85,
"max_score": 50,
"sync_status": "synced",
"sync_error": null,
"submitted_at": "2026-07-27T18:10:00+00:00",
"synced_at": "2026-07-27T18:10:01+00:00"
}
grade_idstring

The grade's ID — use it with GET a grade.

launch_idstring

The launch this grade belongs to.

scorenumber

The submitted fraction (0.0–1.0).

max_scorenumber | null

The max_score you sent, or null if you sent none.

sync_statusstring

pending, synced, or failed. A failed sync still returns 200 — the failure is reported here so you can retry by re-POSTing.

sync_errorstring | null

Why the sync failed, when sync_status is failed.

submitted_atstring

When this score was submitted (ISO 8601). Updated on each resubmission.

synced_atstring | null

When the score reached the gradebook, or null if it hasn't.

Errors​

StatusMessageCause
422score must be between 0 and 1score outside 0.0–1.0.
422max_score must be greater than 0max_score sent as zero or negative.
422activity_progress must be one of [...]Value not Submitted or Completed.
422grading_progress must be one of [...]Value not FullyGraded or Pending.
422This launch's location is not an assessment (grade passback is only allowed for assessment locations)The launched location isn't type assessment.
422Launch has no grade passback (no LMS line item)The LMS never created a gradebook line item for this placement — the launch arrived with grade_passback: false.
404Launch not foundUnknown launch_id, or a launch belonging to a different app (deliberately indistinguishable).
401Missing Bearer API key / Invalid API key / …Authentication problem — see Errors.

Get a grade​

GET /ltiaas/v1/grades/{grade_id}

Returns the same shape as the submit response — useful for checking sync_status later.

curl "https://api.link.voshi.com/ltiaas/v1/grades/Gr8dEx" \
-H "Authorization: Bearer ltiaas_myappid_mysecret"

Unknown grade IDs — and grades belonging to other apps — return 404 Grade not found.