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 record | Grout id | Where it comes from |
|---|---|---|
| Student | users.id + login_email | POST /students response |
| Teacher | users.id + login_email | POST /faculty response |
| Section | groups.id | POST /groups response |
Never derive the login email; always store what the API returned.
Algorithm#
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}/suspendIdempotency and safety#
- Provisioning is not idempotent; check your mapping before creating.
PATCH /groups/{id}withstudent_idsis 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#
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_emailso students skip the mapping screen on first login. - Send students their
login_emailfrom 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.