Skip to content

Guides

Gradebook Sync

Push exam results into your gradebook the moment they are graded.

Flow#

  1. Register a webhook endpoint subscribed to exam.graded (and optionally exam.submitted for "turned in" states).
  2. On exam.graded, fetch the submission for the authoritative numbers.
  3. Write the score to the gradebook item mapped to exam_id.

Handler sketch#

js
app.post('/hooks/grout', express.raw({ type: 'application/json' }), async (req, res) => {
  if (!verifyGrout(req.body.toString(), req.get('X-Grout-Signature'), SECRET)) return res.status(400).end();
  const evt = JSON.parse(req.body);
  res.status(202).end();                       // ack first
  if (await seen(evt.id)) return;              // dedupe on event id
  if (evt.type !== 'exam.graded') return;

  const { data } = await grout(`/submissions/${evt.data.submission_id}`);
  const item = await gradeItemFor(evt.data.exam_id);
  if (evt.data.resubmission_required) await markNeedsRevision(item, data.student_id, data.feedback);
  else await postGrade(item, data.student_id, data.score, data.max_score, data.feedback);
});

Mapping exams to items#

Create the gradebook item when you see exam.published (title, max_score, due_date), store exam_id → item_id, and assign the exam to the section's group. That keeps authoring in Grout and reporting in the LMS.

Backfill#

Missed events? Pull them:

bash
curl "$API/events?type=exam.graded&since=2026-09-01T00:00:00Z" -H "Authorization: Bearer $KEY"
curl "$API/submissions?exam_id=ex_…&status=graded" -H "Authorization: Bearer $KEY"

Or export a whole exam with GET /exams/{id}/export.csv.