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. schools.created
    3. students.created
    4. studentcontacts.created
    5. teachers.created
    6. sections.created
    7. schooladmins.created
  2. Updated
    1. districts.updated
    2. schools.updated
    3. students.updated
    4. studentcontacts.updated
    5. teachers.updated
    6. sections.updated
    7. schooladmins.updated
  3. Deleted
    1. schooladmins.deleted
    2. sections.deleted
    3. teachers.deleted
    4. studentcontacts.deleted
    5. students.deleted
    6. schools.deleted
    7. 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.

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/v1.2/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/v1.2/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

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