Webhooks
Event Catalogue
Every webhook event type, when it fires, and what data it carries.
Every envelope is { id, type, created_at, institution_id, data }. GET /v1/events/types returns this catalogue with a sample payload per type; the portal shows the same under Developers → Deliveries.
People#
| Type | When | data |
|---|---|---|
student.created | Student provisioned (API, portal or batch) | user_id, email, user_type, student_id, source |
student.email_mapped | Personal email linked | user_id, generated_email, student_id, full_name |
student.updated | Status or profile changed via API | user_id, changes[], status? |
faculty.created | Faculty provisioned | user_id, email, user_type, faculty_id |
faculty.profile_completed | Teacher finished first-login profile | user_id, email, employee_id, department, position |
guardian.invited | Guardian link created | student_id, guardian_type, guardian_name |
guardian.verified | Guardian signed in for the first time | student_id, guardian_type |
Licenses#
| Type | When | data |
|---|---|---|
license.generated | License issued | license_id, license_type, user_id, email, expires_at, is_lifetime, max_activations |
license.expired | Passed expiry | license_id, user_id, expires_at |
license.device_registered | New device seat | user_id, app_id, device_name, platform, app_version, kicked |
Exams#
| Type | When | data |
|---|---|---|
exam.published | Exam visible to students | exam_id, title, exam_type, app, faculty_id, due_date |
exam.assigned | Exam assigned to a group | exam_id, group_id, assigned_by |
exam.attempt_started | Student opened the exam | attempt_id, exam_id, student_id, started_at, expires_at |
exam.submitted | Submission (each version) | submission_id, exam_id, student_id, is_late, submitted_at, version, app |
exam.graded | Graded or resubmission requested | submission_id, exam_id, student_id, score, max_score, percentage, resubmission_required, graded_by |
Credits#
| Type | When | data |
|---|---|---|
merits.credited | Wallet credit from any source | email, user_id, amount_cents, reason, balance_after_cents |
coupon.batch_requested | Batch filed for approval | batch_id, count, value_cents, requested_by |
coupon.batch_approved | Grout approved it | batch_id, approved_by |
coupon.redeemed | Code redeemed by your user | coupon_id, user_email, value_cents |
Alpha Learning#
| Type | When | data |
|---|---|---|
alpha.points_awarded | Points ledger entry | student_id, reason, points, ref_type, ref_id, note |
alpha.badge_granted | Badge earned | student_id, badge, title |
System#
| Type | When |
|---|---|
ping | Test event from the portal or POST /webhooks/endpoints/{id}/test |
Wildcards#
Subscriptions accept *, <category>.* (e.g. exam.*) or exact types. Events are deduplicated server-side on (type, ref), so re-running an import does not re-fire student.created for the same email.