Clever Developer Docs

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 and Secure Sync Lite customers.

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.

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

<type>.created events are generated when a new object is created in an SIS or when a district shares an object with your application. Example:

{
  "type": "students.created",
  "data": {
    "object": {
      "school": "530e595026403103360ff9fe",
      "name": {
        "first": "Jean",
        "last": "Grey",              
      },
      "grade": "8",
      "email": "jean.grey@example.net",
      "gender": "F",
      "student_number": "123123123",
      "created": "2015-09-30T21:07:57.525Z",
      "district": "4fd43cc56d11340000000005",
      "dob": "2/11/2007",
      "location": {
        "zip": "10560"
      },
      "last_modified": "2015-09-30T21:07:57.536Z",
      "state_id": "123123123",
      "sis_id": "123123123",
      "id": "530e5960049e75a9262cff1d"
    }
  },
    "created": "2015-09-30T21:08:16.128Z",
    "id": "560c4f4090c0d19590b8d0b0"
}

Updated

<type>.updated events are generated when Clever sees a change on an object. To see which fields have changed, inspect the previous_attributes hash. Example:

"data": {
  "type": "students.updated",
  "data": {
    "object": {
      "sis_id": "5454545",
      "created": "2014-02-26T21:15:12.358Z",
      "location": {
        "zip": "10560"
      },
      "student_number": "5454545",
      "last_modified": "2015-09-30T21:07:57.508Z",
      "gender": "M",
      "grade": "9",
      "name": {
        "first": "Hank",
        "middle": "P",
        "last": "McCoy"
      },
      "dob": "6/18/1998",
      "state_id": "5454545",
      "email": "hank.mccoy@example.net",                    
      "district": "4fd43cc56d11340000000005",
      "school": "530e595026403103360ff9fd",
      "id": "530e5960049e75a9262cff1e"
    },
    "previous_attributes": {
      "name": {
        "first": "Henry"
      },
    }
  },
  "created": "2015-09-30T21:08:15.721Z",
  "id": "560c4f4090c0d19590b8d0b7"
},

Deleted

<type>.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. Example:

"type": "students.deleted",
"data": {
  "object": {
    "created": "2014-02-26T21:15:12.346Z",
    "grade": "8",
    "district": "4fd43cc56d11340000000005",
    "location": {
      "zip": "10560"
    },
    "dob": "2/11/2007",
    "gender": "M",
    "state_id": "987987987",
    "email": "peter.rasputin@example.net",
    "school": "530e595026403103360ff9fe",
    "sis_id": "987987987",    
    "last_modified": "2014-06-04T14:10:40.656Z",
    "name": {
      "first": "Peter",
      "middle": "Nikolaievitch",
      "last": "Rasputin"
    },
    "student_number": "987987987",    
    "id": "530e5960049e75a9262cff1d"
  }
},
"created": "2015-09-21T18:25:59.619Z",
"id": "56004bb84f25d85ba5e38b0d"
},

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. districtadmins.created
    3. schools.created
    4. terms.created
    5. courses.created
    6. students.created
    7. contacts.created
    8. teachers.created
    9. sections.created
    10. schooladmins.created
  2. Updated
    1. districts.updated
    2. districtadmins.updated
    3. schools.updated
    4. terms.updated
    5. courses.updated
    6. students.updated
    7. contacts.updated
    8. teachers.updated
    9. sections.updated
    10. schooladmins.updated
  3. Deleted
    1. schooladmins.deleted
    2. sections.deleted
    3. teachers.deleted
    4. contacts.deleted
    5. students.deleted
    6. terms.deleted
    7. courses.deleted
    8. schools.deleted
    9. districtadmins.deleted
    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 user.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/v2.0/events?ending_before=last&limit=1
  2. Perform an initial sync using the non-events endpoints: districts, schools, students, teachers, 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/v2.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 students, 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:

Updating Data with Events