Updating Data with Events

Data retrieved from the Clever API serves as a "snapshot" of what currently exists in a district's student information system. However, sometimes it can be valuable to pull in the deltas, and avoid the overhead of pulling down all data. You can also use events to see how this data came to be in the state it's currently in via a "timeline" view. Clever's events endpoint provides a 30-day window that describes changes to a district's data.

Events are only available to Secure Sync customers.

🚧

Events from other API Versions

Please note: Events for fields and objects that are introduced in later API versions will not appear in this version of the API. Please be sure to review the available events for your specific API version.

❗️

If you are using events, you should be able to perform an initial sync or resync directly from the Data API (students, teachers, etc.) The Events API is offered only as a convenience for keeping up with changes. Processing data from the events endpoints should be idempotent, meaning that processing the same event multiple times should result in no change of state.

Enabling events

📘

Events opt-in changes

Starting December 2022, events will be opt-in only. If you are not currently using events in production, you will need to enable events to use them moving forward.

To enable events, go to Settings > Integrations > Enable events. Once events are enabled, Clever will begin generating events for all connected districts.

2506

If you disable events, Clever will stop generating new events for changes in district data.

How long are events stored?

Events are stored for a period of 30 days. The event feed is sorted from older to newest, and after 30 days events are removed from our system. Events that are 31+ days old will be removed from the events timeline, i.e. the "top" of the events list.

Anatomy of an event

Event JSON data objects contains the following fields:

type: Type of event. See Event Types for more detail.
data: Full JSON of object in clever that was created, updated, or deleted.
id: Clever ID of the event. Not to be confused with the Clever ID of the data object represented in the event
created: Timestamp that the event was created. This should be used for informational purposes

Events also contain the usual paging and links fields found in the Clever API.

Event types

Created

users.created events are generated when a new object is created in an SIS or when a district shares an object with your application. Notice in the example below that you can identify the user type based on the "roles" node.

Example:

{
	"data": {
		"created": "2021-12-02T17:15:46.000Z"
		"data": {
			"object": {
				"created": "2020-11-10T17:07:23.909Z"
				"district": "58da8a43cc70ab00017a1a87"
				"email": "[email protected]"
				"id": "58da8c65d7dc0ca06800074b"
				"last_modified": "2021-12-02T17:05:51.925Z"
				"name": {
					"first": "Helen"
					"last": "Fisher"
					"middle": "J"
				}
				"roles": {
					"student": {
						...
					}
				}
			}
		}
		"id": "61a8ff42a2df9b130cf6509c"
		"type": "users.created"
	}
	"uri": "/v3.0/events/61a8ff42a2df9b130cf6509c"
}

Updated

users.updated events are generated when Clever sees a change on an object. To see which fields have changed, inspect the previous_attributes hash. Notice in the example below that you can identify the user type based on the "roles" node.
Example:

"data": {
	"created": "2021-11-14T17:06:55.000Z"
	"data": {
		"object": {
			"created": "2020-11-10T17:07:22.367Z"
			"district": "58da8a43cc70ab00017a1a87"
			"email": "[email protected]"
			"id": "58da8c63d7dc0ca068000447"
			"last_modified": "2021-11-11T17:05:58.926Z"
			"name": {
				"first": "Pedro"
				"last": "Bauch"
				"middle": "D"
			}
			"roles": {
				"student": {
					"credentials": {
						"district_username": "pedrob07"
					}
					"dob": "8/1/2000"
					"enrollments": []
					"ext": {
						"gifted_status": ""
					}
					"gender": "M"
					"grade": "7"
					"graduation_year": ""
					"hispanic_ethnicity": "N"
					"location": {
						"address": ""
						"city": ""
						"state": ""
						"zip": "10017"
					}
					"race": "Black or African American"
					"school": "58da8c58155b940248000008"
					"schools": [
						"58da8c58155b940248000007"
						"58da8c58155b940248000008"
					]
					"sis_id": "180999707"
					"state_id": "399605649"
					"student_number": "180999707"
				}
			}
		}
		"previous_attributes": {
			"roles": {
				"student": {
					"ext": {
						"gifted_status": "Y"
					}
				}
			}
		}
	}
	"id": "6191422ff93d5a03e33d2f7e"
	"type": "users.updated"
}
"uri": "/v3.0/events/6191422ff93d5a03e33d2f7e"
}

Deleted

users.deleted events are generated when Clever sees than an object was removed from an SIS or when a district unshares an object with your application. Notice in the example below that you can identify the user type based on the "roles" node.

Example:

"data": {
	"created": "2021-11-30T17:09:15.000Z"
	"data": {
		"object": {
			"created": "2021-11-25T17:06:03.838Z"
			"district": "58da8a43cc70ab00017a1a87"
			"email": "[email protected]"
			"id": "5fad6ba2b84acb058bf8dc22"
			"last_modified": "2021-11-25T17:06:03.838Z"
			"name": {
				"last": "Wanell Schmeler"
			}
			"roles": {
				"contact": {
					"legacy_id": "5f75fe4d64cf6b128cecda56"
					"phone": ""
					"phone_type": "Other"
					"relationship": "Other"
					"sis_id": ""
					"student_relationships": [...]
					"students": [
						"58da8c65d7dc0ca0680006b6"
					]
					"type": "Family"
				}
			}
		}
	}
	"id": "61a65abb7d8210097c2d9046"
	"type": "users.deleted"
}
"uri": "/v3.0/events/61a65abb7d8210097c2d9046"
}

Event ordering

Clever generally receives batch data updates from districts that include a mix of creates, deletes, and updates. When we process the data from a batch, we intentionally sequence events to make it easy for your application to process the data. Here’s the ordering of events you should expect to see within a batch:

🚧

Please note: You will receive events in the order they are generated - in the case where a single sync / sharing change creates multiple events, we will order them as described below.

Your integration should process events in the order they are received, not by event type.

  1. Created
    1. districts.created
    2. users.created (District Admins)
    3. schools.created
    4. terms.created
    5. courses.created
    6. users.created (Students)
    7. users.created (Contacts)
    8. users.created (Teachers)
    9. sections.created
    10. users.created (Staff)
  2. Updated
    1. districts.updated
    2. users.updated (District Admins)
    3. schools.updated
    4. terms.updated
    5. courses.updated
    6. users.updated (Students)
    7. users.updated (Contacts)
    8. users.updated (Teachers)
    9. sections.updated
    10. users.updated (Staff)
  3. Deleted
    1. users.deleted (Staff)
    2. sections.deleted
    3. users.deleted (Teachers)
    4. users.deleted (Contacts)
    5. users.deleted (Students)
    6. terms.deleted
    7. courses.deleted
    8. schools.deleted
    9. users.deleted (District Admin)
    10. districts.deleted

Note: You will only ever see one districts.created event per district-app token, and there is no event that will alert you to new districts being connected. districts.deleted events are technically generated, but in practice you will never see them as the district-app token will no longer be valid.

Note: Changes to student and teacher enrollments are reflected in sections.updated events, not users.updated events.

Setting up an events sync

Requests made directly to the /events endpoint are scoped to a single district based on the use of a district-app token for authorization.

This is the recommended flow for working with events:

  1. Make a request to obtain the single most recent event and save its ID
    GET https://api.clever.com/v3.0/events?ending_before=last&limit=1
  2. Perform an initial sync using the non-events endpoints: districts, schools, users, sections
  3. On subsequent syncs, request the events that are "new" -- those that begin after the previously processed event id:
    GET https://api.clever.com/v3.0/events?starting_after=<event id>
  • The starting_after parameter requires a valid event_id, so if there is no previously processed event, then omit the parameter
  • If there are no events after that ID, we will return an empty array

Syncing events on a per-school basis

We now include a school parameter that you can use to retrieve all event records associated with a specific school. It will return events for resources where the specific school is listed as either a primary school (in the school field) or as a non-primary school (in the students array).

Use of the school parameter does not apply to the following resources because they are associated with districts, not schools.

  • Courses
  • Terms
  • Contacts

Syncing specific record types

We now provide the ability to query for specific record types (e.g. only users, or only sections). This can be helpful if you are only interested in updating data for specific data types. Otherwise, we generally recommend processing data from the event stream in the order we sequence it.

If you choose to use the record_type parameter, process events in the order below. Barring any constraints specific to your application, the order within groups does not matter (e.g. students vs. teachers).

  1. Districts
  2. Schools
  3. Users
  4. Contacts
  5. Terms & Courses
  6. Sections

🚧

If your sync uses events, you must still have the ability to resync via the Data API. This is because:

  • During school year rollover, districts may generate more events than the total number of records in the district. In this case, doing a full data resync is more efficient than processing events
  • If for any reason your database no longer matches the data set in Clever, performing a full data resync is the only way to rematch the data sets.

Processing events

Events must be processed in chronological order, as they are presented in our API. Processing events in a different order significantly increases the chances of sync errors.

In order to ensure parity, inspect the Clever ID of the object in your database before performing any action. See this flowchart for more detail:

1404

What’s Next