Skip to main content

Webhook event list

Your webhook endpoint receives the following JSON bodies through HTTP POST and acknowledges delivery with HTTP 2xx. See Webhook integration for configuration, headers, signatures and retries.

The following ten events are supported. IDs, names, URLs, times and error messages illustrate the payload format. Optional fields may be absent; use the corresponding query API for complete resource details.

Event index​

EventMeaningState in the example
classroom.createdClassroom createdpending
classroom.updatedClassroom updatedpending
classroom.startedClassroom startedlive
classroom.endedClassroom endedended
classroom.expiredClassroom expiredexpired
classroom.stage_changedMember stage occupancy changedlive
courseware.createdCourseware createdqueued
courseware.processingCourseware processingprocessing
courseware.readyCourseware readyready
courseware.failedCourseware failedfailed

Envelope and classroom fields​

FieldTypeRequiredMeaning
eventIdstringYesUnique event ID; stable across retries
typestringYesFull event name
appIdstringYesOwning application
timestampstringYesEvent creation time in ISO 8601
dataobjectYesEvent-specific data

Classroom events share these data fields:

FieldTypeRequiredMeaning
classroomIdstringYesClassroom ID
namestringYesClassroom name at the event
statusstringYesState after the change: creating, pending, live, ended or expired
teacherEduUserIdstringNoTeacher ID when assigned

Classroom created​

classroom.created

Sent after classroom creation completes and its state is saved. Use it to associate your course with the classroom; it does not indicate client entry.

Additional data fieldTypeRequiredMeaning
fromStatusstringYesPrevious creation state, currently creating.

Immediate start also produces a separate classroom.started event; this event can already have status: live.

{
"eventId": "evt_example_classroom_created",
"type": "classroom.created",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"classroomId": "cls_example",
"name": "Math class",
"status": "pending",
"teacherEduUserId": "eu_teacher",
"fromStatus": "creating"
}
}

Classroom updated​

classroom.updated

Sent after a classroom name or configuration update. Use it to refresh your stored classroom details.

Additional data fieldTypeRequiredMeaning
teacherChangedbooleanYesWhether this update changed the teacher.

The notification contains the common classroom fields and teacherChanged, not a full configuration snapshot. Query the classroom API for details.

{
"eventId": "evt_example_classroom_updated",
"type": "classroom.updated",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"classroomId": "cls_example",
"name": "Math class",
"status": "pending",
"teacherEduUserId": "eu_teacher",
"teacherChanged": false
}
}

Classroom started​

classroom.started

Sent when a classroom enters live. Use it to update course state or start in-class workflows.

Additional data fieldTypeRequiredMeaning
fromStatusstringYesClassroom state before starting.
sourcestringYesStart source; values below.
startsAt / endsAtstringNoScheduled start/end, ISO 8601.
actualStartedAtstringNoActual start, ISO 8601.
effectiveEndsAtstringNoEffective end based on actual start, duration and overtime, ISO 8601.

source: create_immediate (start during creation), manual, auto_reconcile (state reconciliation), auto_job (scheduled job), or lazy_refresh (refresh during a query). Time fields are included when available. This event does not establish client IM, RTC or whiteboard readiness.

{
"eventId": "evt_example_classroom_started",
"type": "classroom.started",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"classroomId": "cls_example",
"name": "Math class",
"status": "live",
"teacherEduUserId": "eu_teacher",
"fromStatus": "pending",
"source": "manual",
"startsAt": "2026-10-09T02:00:00.000Z",
"endsAt": "2026-10-09T03:00:00.000Z",
"actualStartedAt": "2026-10-09T02:00:00.000Z",
"effectiveEndsAt": "2026-10-09T03:00:00.000Z"
}
}

Classroom ended​

classroom.ended

Sent after a live classroom ends manually or automatically. Use it to close the in-class state and begin archival work.

Additional data fieldTypeRequiredMeaning
fromStatusstringNoPrevious state; batch-ending paths may omit it.

The event does not contain attendance totals, recording URLs or an actual-end-time field. Delivery time is not a course statistics result.

{
"eventId": "evt_example_classroom_ended",
"type": "classroom.ended",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"classroomId": "cls_example",
"name": "Math class",
"status": "ended",
"teacherEduUserId": "eu_teacher",
"fromStatus": "live"
}
}

Classroom expired​

classroom.expired

Sent when an unstarted classroom meets the server expiration condition and becomes expired. Use it to mark the scheduled classroom as expired.

Additional data fieldTypeRequiredMeaning
fromStatusstringNoPrevious state; batch-expiration paths may omit it.

This differs from classroom.ended after a class has started. It does not include an expiration-reason enum or a rescheduling result.

{
"eventId": "evt_example_classroom_expired",
"type": "classroom.expired",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"classroomId": "cls_example",
"name": "Math class",
"status": "expired",
"teacherEduUserId": "eu_teacher",
"fromStatus": "pending"
}
}

Member stage occupancy changed​

classroom.stage_changed

Sent when a member moves between occupied (on) and unoccupied stage states. Use it to synchronize stage membership or record stage activity.

Additional data fieldTypeRequiredMeaning
actionstringYeson: take a seat; off: leave the stage.
eduUserIdstringYesID of the affected member.
rolestringYesMember role in this classroom.
fromStageStatus / stageStatusstringYesPrevious/new state: off, hand_raised, on.
actorEduUserIdstringNoActor ID when available.
sourcestringYesSource of the change; values below.
onStageCountnumberYesStage occupant count after the change, integer.

source: invite, accept_hand, join, fill_on_start, backfill, leave_stage, leave_classroom, roster_removed, trtc_exit, im_offline, im_timeout. Raising, cancelling or rejecting a hand does not emit it. join refers to entry that changes occupancy, not every classroom entry.

{
"eventId": "evt_example_classroom_stage_changed",
"type": "classroom.stage_changed",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"classroomId": "cls_example",
"name": "Math class",
"status": "live",
"teacherEduUserId": "eu_teacher",
"action": "on",
"eduUserId": "eu_student",
"role": "student",
"fromStageStatus": "hand_raised",
"stageStatus": "on",
"actorEduUserId": "eu_teacher",
"source": "accept_hand",
"onStageCount": 2
}
}

Courseware fields​

All four courseware events share these data fields. Each event's additional fields are listed below its heading.

FieldTypeRequiredMeaning
coursewareIdstringYesCourseware ID
namestringYesCourseware name
formatstringYesFile format, for example pdf
statusstringYesqueued, processing, ready or failed
progressnumberYesConversion progress, 0–100
ownerEduUserIdstringNoOwner ID when recorded
jobIdstringNoConversion job ID when recorded
errorCode / errorMessagestringNoRecorded error code/message
resultManifestUrlstringNoConversion manifest URL when available
coursewareBaseUrlstringNoConverted-resource base URL when available

Only the creation event adds a classroom binding ID. Do not require it on later conversion events.

Courseware created​

courseware.created

Sent after the courseware record is created. Use it to associate an upload task with a courseware ID.

Additional data fieldTypeRequiredMeaning
fromStatusstringYesAlways queued.
classroomIdstringNoClassroom requested for binding during creation.

This event uses a creation snapshot with status: queued and progress: 0. An immediate conversion failure produces this event and a separate failure event.

{
"eventId": "evt_example_courseware_created",
"type": "courseware.created",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"coursewareId": "cw_example",
"name": "lesson.pdf",
"format": "pdf",
"status": "queued",
"ownerEduUserId": "eu_teacher",
"progress": 0,
"fromStatus": "queued",
"classroomId": "cls_example"
}
}

Courseware processing​

courseware.processing

Sent when creation, retry or a conversion update moves courseware into processing. Use it to display conversion in progress.

Additional data fieldTypeRequiredMeaning
fromStatusstringYesPrevious state; can be failed for a retry.

Progress changes while already processing do not emit an event each time. A retry does not emit another courseware.created.

{
"eventId": "evt_example_courseware_processing",
"type": "courseware.processing",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"coursewareId": "cw_example",
"name": "lesson.pdf",
"format": "pdf",
"status": "processing",
"ownerEduUserId": "eu_teacher",
"progress": 0,
"jobId": "job_example",
"fromStatus": "queued"
}
}

Courseware ready​

courseware.ready

Sent when conversion makes courseware ready. Use it to refresh availability and resource locations.

Additional data fieldTypeRequiredMeaning
fromStatusstringYesState before becoming ready.

Resource URLs come from conversion results and are included when available. Query classroom bindings separately; classroomId is not guaranteed. Respect resource access controls and expiration.

{
"eventId": "evt_example_courseware_ready",
"type": "courseware.ready",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"coursewareId": "cw_example",
"name": "lesson.pdf",
"format": "pdf",
"status": "ready",
"ownerEduUserId": "eu_teacher",
"progress": 100,
"jobId": "job_example",
"fromStatus": "processing",
"resultManifestUrl": "https://assets.example.com/courseware/manifest.json",
"coursewareBaseUrl": "https://assets.example.com/courseware/"
}
}

Courseware failed​

courseware.failed

Sent when starting conversion fails or a conversion result makes courseware failed. Use it to display the failure and decide whether to retry.

Additional data fieldTypeRequiredMeaning
fromStatusstringYesPrevious state, such as queued or processing.

errorCode and errorMessage are included only when recorded; do not match the illustrative message in business logic. A start failure may have no jobId.

{
"eventId": "evt_example_courseware_failed",
"type": "courseware.failed",
"appId": "app_example",
"timestamp": "2026-10-09T02:00:00.000Z",
"data": {
"coursewareId": "cw_example",
"name": "lesson.pdf",
"format": "pdf",
"status": "failed",
"ownerEduUserId": "eu_teacher",
"progress": 0,
"fromStatus": "queued",
"errorMessage": "Conversion could not be started."
}
}

Reserved events​

The following entries are reserved in the subscription catalog and do not send notifications.

Catalog entryIntended meaning indicated by the nameCurrent delivery
edu_user.registeredUser registrationNot emitted
classroom.member_addedMember added to rosterNot emitted
classroom.joinedUser joined a classroomNot emitted
classroom.permission_grantedClassroom permission grantedNot emitted
classroom.permission_revokedClassroom permission revokedNot emitted
classroom.feature_status_changedClassroom feature status changedNot emitted

media.im_callback, media.trtc_callback and media.live_callback are internal media events, excluded from customer subscriptions. Client callbacks are documented in Client APIs and events.

Webhook user IDs, classroom names and resource URLs must be included in the receiver's data handling inventory. See Data collection.