On first full sync, record the UTC timestamp immediately before the sync begins as your cursor; store cursor per endpoint (orgs, users, classes, enrollments) in persistent storage.
On subsequent runs, request each endpoint with filter=dateLastModified>'<cursor_timestamp>' to retrieve only changed records; use ISO 8601 format in UTC (e.g., 2025-09-01T00:00:00.000Z).
Inspect the status field on each returned record: 'active' means create-or-update; 'tobedeleted' means remove the record from your system.
Apply upsert logic keyed on sourcedId — if the record already exists in your store, update it; if not, insert it; if status is 'tobedeleted', delete it.
After processing all pages, advance the cursor to the timestamp recorded at the start of this run (not the current time) to avoid missing records written during the sync window.
Implement a full resync fallback: if the delta returns no results but your system detects divergence (e.g., enrollment count mismatch), trigger a full pull and rebuild from scratch.
Known gotchas
Using the current timestamp as the new cursor after sync completes can skip records written between the old cursor and the moment you set the new cursor; always capture the cursor before calling the API.
Some OneRoster providers do not update dateLastModified when only a relationship changes (e.g., a user's role in a class); supplement date-based delta with periodic count reconciliation.
The OneRoster spec does not mandate that servers retain tombstone records indefinitely; if a provider purges 'tobedeleted' records after a short window, a slow consumer will miss deletions — negotiate a minimum retention period with the provider.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp