# LMS Integration

> Connect Moodle, Canvas or any LMS to GroutApp and GroutCode: roster sync and gradebook write-back on one institution API.

Canonical: https://grout.app/developer/documentation/guides/lms-integration/

Grout integrates with a learning management system through two jobs. Each one is a small piece of code on your side, uses its own API key, and can be adopted independently.

| Job | What it does | Scopes | Guide |
|---|---|---|---|
| **Roster sync** | Mirrors students, faculty and sections from your SIS or LMS into Grout | `students:write`, `faculty:write`, `groups:write` | [Roster Sync](/developer/documentation/guides/roster-sync/) |
| **Gradebook write-back** | `exam.graded` webhooks push scores into the LMS gradebook | `submissions:read`, `webhooks:write` | [Gradebook Sync](/developer/documentation/guides/gradebook/) |

There is no LMS plugin to install. Everything runs over plain HTTPS and JSON against `https://serverless.grout.app/v1`, so the same code works for Moodle, Canvas, Blackboard, a homegrown portal or an LTI tool.

## How the pieces fit

```text
SIS / LMS ──(nightly)──► POST /students, /faculty, /groups ──► Grout institution
Grout grades exam ──(event)──► exam.graded webhook ──► your handler ──► LMS gradebook
```

1. **Provision people once.** Your sync creates each student with `student_id` set to the SIS id, stores the returned `id` and `login_email`, and keeps one Grout group per section. Membership is replaced on every run, so groups never drift. Students sign in to the apps themselves with the login email and a one-time code; pre-map `personal_email` so the code reaches them on the first try.
2. **Get results back.** Exams created through the API are graded in Grout. Subscribe an endpoint to `exam.graded`, verify the signature, fetch the submission for the authoritative score, and write it to the gradebook item mapped to `exam_id`.

## Platform guides

:::cards
- [Moodle](/developer/documentation/guides/moodle/) — Web-services roster sync and `core_grades_update_grades` for scores.
- [Canvas](/developer/documentation/guides/canvas/) — Sections API and `posted_grade` on assignments.
- [Roster Sync](/developer/documentation/guides/roster-sync/) — The LMS-agnostic algorithm, mappings and safety rules.
- [Gradebook Sync](/developer/documentation/guides/gradebook/) — Handler sketch, exam-to-item mapping, backfill.
:::

## Keys and scopes

Create one key per job in the portal (**Institution → Developers → API keys**). A leaked roster key cannot then read submissions, and a gradebook key cannot create people.

```text
lms-roster     students:write faculty:write groups:write        600/min
lms-gradebook  submissions:read webhooks:write                   100/min
```

Every key is bound to your institution. No request accepts an `institution_id`, so a key can never touch another school's data. See [API Keys & Scopes](/developer/documentation/setting-up/api-keys/).

## Sizing

A 5 000-student institution syncs within the default 600 requests per minute: `POST /students/bulk` takes 200 students per call, and `PATCH /groups/{id}` is one call per section. Webhook deliveries are pushed to you, so gradebook write-back costs nothing against the limit beyond one `GET /submissions/{id}` per graded attempt.

## Checklist before go-live

- `GET /v1/me` with each key shows exactly the scopes above.
- Roster sync stores `id` and `login_email` from the API response, never derives them.
- Webhook handler verifies `X-Grout-Signature`, acks within 10 seconds, and dedupes on the event `id`.
- A test exam assigned to a test group produces a grade in the LMS end to end.
- Suspend, don't delete, students who leave.

:::tip Automating the integration with an agent
Every page here is readable as markdown by appending `.md` to its path, and [llms.txt](/developer/llms.txt), [AGENTS.md](/developer/AGENTS.md) and [SKILLS.md](/developer/SKILLS.md) give a coding agent the endpoints, scopes and request templates for each job.
:::

Read [Integration Best Practices](/developer/documentation/guides/integration-best-practices/) next: idempotency, backoff, secret handling and monitoring for anything that talks to this API.
