- Listen to our data-changed webhook to receive notifications of data changes.
- Fetch only updated data.
- Periodically fetch all data to fully align your dataset and correct any potential data drift.
- Combine both strategies for a setup that is robust and efficient.
Overview
Listening to data-changed webhook
We provide a webhook calleddata-changed. This is sent to your system whenever
data has changed inside Kombo, for example after we finish syncing (full or delta sync).
By listening to this webhook, you can receive updates from Kombo efficiently,
allowing for the best possible UX.
The webhook will look similar to this, with an array of models that have changed
in our database since we last sent you that webhook:
/courses endpoint to fetch both courses and their
associated skills.
Furthermore, after every successful fetch from us, store the timestamp of when
the respective fetch started. Use this timestamp during your next fetch and pass
it with your requests to the Kombo API as the updated_after query parameter.
Kombo will then only return the entries that changed since that timestamp.
Good to know: The updated_after filter also considers changes in models
that are returned by the endpoint as nested values. For example, the
/course-progressions endpoint will include every progression that has had
changes to related courses or users, even if the progression itself did not
change. Read more below.
All models
You should call the endpoints you care about based on the models we tell you have changed. The following table shows endpoints connected to the relevant models that will be part of the data-changed webhook. We recommend the following approach:- Decide which endpoints are relevant for your use case (e.g., if your system is centered around course completions, you primarily use Get course progressions).
- Map changed models to those endpoints using the table.
For instance, if both lms_course_progressions and lms_courses are listed in the webhook, but you primarily care about progressions, you only need to call Get course progressions, since course data is included there too.
| Endpoint | Models |
|---|---|
| Get users | lms_users |
| Get courses | lms_courses lms_course_revisions lms_course_providers lms_skills lms_join_revisions_skills |
| Get course progressions | lms_course_progressions lms_courses lms_course_revisions lms_users |
Preventing Data Drift
In addition to fetching data from Kombo’s endpoints in response to receiving the data-changed webhook, we recommend running a periodic full data fetch for the data models you care about. In most cases, a 7-day schedule is ideal. This helps to remedy any drift that may occur in your data, e.g. from accidental manual changes or lost webhooks. To implement this, perform GET requests for the Kombo data models you care about without passing theupdated_after query parameter. Then upsert the data
returned by Kombo and merge it with your existing data copy.
Full Example Code
Understanding changed_at vs updated_after Behavior
A common source of confusion is understanding when records are returned by the
updated_after filter and how this relates to each record’s changed_at
timestamp. Here’s the key distinction:
Record-level changed_at Field
Each record has a changed_at timestamp that only updates when properties
directly on that record change. For example:
- If a course’s
titlechanges, the course’schanged_atupdates - If a progression’s
statuschanges, the progression’schanged_atupdates - However: If a course’s title changes, related progressions’
changed_atfields do NOT update
Endpoint Filtering with updated_after
The updated_after parameter works differently - it returns records when
either the record itself OR its nested data has been updated:
Example: Course Progressions Endpoint
When you callGET /course-progressions with updated_after, you’ll receive
progressions if:
- Direct progression changes: The progression itself was modified (status, enrolled_at, etc.)
- Nested course revision changes: The course revision data was updated (title, description, etc.)
- Nested user changes: The user data was updated (name, email, etc.)
changed_at timestamp
hasn’t changed.
Concrete Scenario
Let’s say you callGET /course-progressions at 9:00 AM and get:
GET /course-progressions?updated_after=2023-10-01T09:00:00Z, you’ll receive:
changed_at remains unchanged, but the
progression is still returned because it contains updated nested course data.
Best Practice
When usingupdated_after filtering:
- Don’t assume a record was directly modified just because it’s returned
- Compare nested data to determine what actually changed
- Use the nested objects’
changed_atfields to identify which parts were updated - Design your sync logic to handle both direct and indirect changes