Skip to content

Guides

Roster Sync

A generic, LMS-agnostic recipe for keeping Grout people and groups in step with your SIS.

Data model#

Keep three mappings on your side:

Your recordGrout idWhere it comes from
Studentusers.id + login_emailPOST /students response
Teacherusers.id + login_emailPOST /faculty response
Sectiongroups.idPOST /groups response

Never derive the login email; always store what the API returned.

Algorithm#

text
for each teacher in SIS:        ensure faculty  (POST /faculty if missing)
for each student in SIS:        ensure student  (POST /students or /students/bulk if missing)
                                PATCH /students/{id} if name/personal_email changed
for each section in SIS:        ensure group    (POST /groups if missing)
                                PATCH /groups/{id} { student_ids: [...] }   # replaces membership
for each student no longer enrolled anywhere: POST /students/{id}/suspend

Idempotency and safety#

  • Provisioning is not idempotent; check your mapping before creating.
  • PATCH /groups/{id} with student_ids is a full replace — compute the list from the SIS, do not merge.
  • Suspend, don't delete. Suspended students keep their license and history.
  • Run under a key with only students:write, faculty:write, groups:write.

Verifying a run#

bash
curl "$API/students?status=pending&limit=200" -H "Authorization: Bearer $KEY"   # never signed in
curl $API/licenses/summary -H "Authorization: Bearer $KEY"
curl "$API/events?type=student.*&since=<run start>" -H "Authorization: Bearer $KEY"

First-run tips#

  • Pre-map personal_email so students skip the mapping screen on first login.
  • Send students their login_email from your own system; the API does not email students on creation.
  • Faculty first logins route the OTP to the institution admin's mailbox until the teacher completes their profile.