Integrations

How to sync OneRoster (1EdTech) data with Kastr

Kastr's roster model is OneRoster-shaped by design, which means a district already producing a OneRoster bundle for another application is most of the way there. This page is the translation layer the 1EdTech specification deliberately does not provide: which files we read, which we ignore, exactly where each field lands, and what happens when your broker regenerates its identifiers.

Last reviewed 2026-08-04 ยท Kastr is pre-launch; we publish dated status rather than logos.

The OneRoster v1.1 CSV file set, and what Kastr does with each file
FileStatusWhat Kastr takes from itWhy
manifest.csvRead if presentVersion and file inventoryTells us whether to expect v1.1 agents or v1.2 relationships
orgs.csvRequiredDistricts and schools, and the parent hierarchyBecomes the org tree that row-level security enforces against
users.csvRequiredPeople, roles, identifiers, phone, SMS, email, languageEvery identity and contact point comes from here
enrollments.csvRequiredWho is in which class, in which role, over which datesEffective dating is how a withdrawal is distinguished from a disappearance
relationships.csv (v1.2)Required in v1.2Guardian-to-student edgesThe whole point of a communications roster
classes.csvOptionalSection names and schoolStored; not yet usable as an audience filter
courses.csvOptionalCourse titlesContext only
academicSessions.csvOptionalTerms and grading periodsUsed to date enrolments when dates are absent
demographics.csvIgnoredNothingRace, ethnicity, birth date and gender are not needed to send a message
categories.csv, lineItems.csv, results.csvIgnoredNothingGradebook. Out of scope, deliberately

If your bundle contains the ignored files, send them anyway — they are skipped, not rejected. We would rather you not build a custom export than have you strip files to satisfy us. The demographics file is ignored on purpose: a communications platform that holds race and ethnicity data has acquired a breach-notification liability in exchange for nothing.

Field-level mapping

Where each field you care about ends up:

  • users.sourcedIdexternal identifier. This is the match key for the diff engine. Its stability is the single most important property of your feed.
  • users.rolean effective-dated role on a person, not a type on a record. A user with role parent and role teacher in two rows becomes one person with two roles, provided the identifiers resolve to the same human.
  • users.agents (v1.1) or relationships.csv (v1.2) → guardian-to-student edges. Order in the agents array becomes contact rank, which is the only ordering signal v1.1 gives you.
  • users.phone, users.sms, users.emailseparate contact points. The distinction between phone and sms is the one field most implementations populate carelessly and it decides whether we text a number or call it. If only phone is present, we treat it as voice-capable and not SMS-capable, which is the conservative reading.
  • users.givenName, familyName, preferredFirstName → display names, with the preferred name winning in family-facing output.
  • users.metadata.language or an equivalent extension → language preference, which selects the translation target. Populate it per guardian rather than per student; a household where the student speaks English and the parent does not is the normal case, not the edge case.
  • orgs.parentSourcedIdthe organisation hierarchy, which is what row-level security evaluates against. Get this wrong and a school ends up outside its district.
  • enrollments.beginDate and endDateeffective dating on the role. An enrolment with an end date in the past classifies as a withdrawal without needing the student to be absent from the file.

Every contact point that lands carries a validationState, a consentState for 10DLC and TCPA purposes, a source and a rank. OneRoster carries none of those four concepts, so they are derived: source becomes the sync, consent defaults to your district's configured position, and validation is computed on the value itself.

v1.1 versus v1.2, specifically for guardian data

The versions differ in more places than this, but for a communications roster there is really one difference that matters.

v1.1 expresses guardianship as an agents array on the user: a student's user row lists the sourcedIds of the adults associated with them. It is compact, it is ordered, and it carries no relationship semantics at all. You know an adult is associated with a student. You do not know whether they are a mother, a court-appointed guardian, or an emergency contact who should never receive a routine message.

v1.2 introduces a proper relationships model with a relationship type, which is a real improvement and still leaves you short of what a SIS knows. There is no educational-rights flag, no correspondence preference, no restriction indicator.

The practical consequence: a OneRoster feed alone rarely carries enough guardian semantics to message safely. That is not a criticism of the standard, which was written for learning applications rather than for notification systems. It is the reason nearly every page in this cluster recommends taking students, staff and sections from OneRoster and guardian detail from a small purpose-built SIS extract.

If your broker still emits v1.1, that is fine. Send it. The rank ordering from the agents array is used, relationship type is recorded as unknown, and the supplementary contacts file fills the gap.

sourcedId stability, and what breaks when it changes

The diff engine hashes each record payload with SHA-256 and matches on the external identifier. A stable identifier means yesterday's Maria and today's Maria are the same Maria. An unstable one means they are a withdrawal and an addition.

Identifiers change more often than anyone expects. A broker reconfiguration regenerates them. A SIS upgrade changes their format. A well-intentioned engineer strips leading zeros in a transformation step. A district switches from local to state student numbers halfway through a year.

What a full identifier change looks like: a 12,000-student district posts a file where every sourcedId differs. The engine computes 12,000 additions and 12,000 withdrawals. Withdrawals exceed 50% of active records, so the run aborts as aborted_guardrail, nothing is written, and yesterday's roster stands. You get an alert instead of an incident.

The safe way to change identifiers deliberately: run a dry run first, confirm the ledger shows the symmetrical add/withdraw pattern you expect, then re-key with a mapping file rather than letting the diff engine work it out. Doing it by accident is what the guardrail is for; doing it on purpose is a planned migration.

One person appearing under two identifiers — the guardian who is also a teacher, present in users.csv twice with different roles and different sourcedIds — collapses to a single identity on matching contact points, and both roles attach to that one person with their own effective dates. This is worth verifying on your own data during onboarding, because it is the behaviour that most distinguishes the model and the one that fails most visibly if the source data disagrees with itself.

A minimum viable bundle

You do not need the full file set to get a clean dry run. The smallest bundle that works is four files:

  1. orgs.csv with your district and its schools, and correct parentSourcedId values.
  2. users.csv with students and guardians, roles, identifiers and contact fields.
  3. enrollments.csv tying students to a school, with begin and end dates.
  4. Guardian edges — the agents column on users.csv in v1.1, or relationships.csv in v1.2.

Twenty fabricated records in that shape is enough to POST with --dry-run and read the full ledger, which is the recommended first hour of any implementation. Build it against fake data, watch the classification, then point the same job at the real export.

To answer the question directly: Kastr is not a 1EdTech-certified OneRoster consumer. We have not gone through certification. The data model follows the standard and the importer reads the standard file set, but if your procurement requires a certification mark on a vendor list, we do not have one and will not pretend the shape of our schema is the same thing.

Questions people actually ask

Which OneRoster CSV files does Kastr actually require, and which can I leave out?

Required: orgs, users, enrollments, and guardian edges — either the agents column in v1.1 or relationships.csv in v1.2. Optional and used if present: classes, courses, academicSessions. Ignored entirely: demographics and all three gradebook files. Send them anyway if your export produces them; they are skipped, not rejected.

Does Kastr support OneRoster v1.2, and what changes for guardian relationships?

Both versions are read. v1.2 replaces the v1.1 agents array with a relationships model carrying a relationship type, which is better. Neither version carries educational rights, correspondence preferences or contact restrictions, which is why we recommend supplementing any OneRoster feed with a small guardian extract straight from the SIS.

What happens if my SIS or broker regenerates sourcedIds between syncs?

Every record reads as a withdrawal plus an addition. If that exceeds 50% of active records the run aborts as aborted_guardrail and writes nothing, which is the outcome you want. If you are changing identifiers deliberately, dry-run first and re-key with a mapping file rather than letting the diff engine discover it.

How does Kastr handle one person who is both a guardian and a teacher?

One person record with two effective-dated roles. If OneRoster gives you two user rows with different sourcedIds, they collapse to a single identity on matching contact points and both roles attach. Broadcasts de-duplicate across roles, so an all-staff message and a guardian message never arrive twice for the same reason.

Is Kastr a 1EdTech-certified OneRoster consumer?

No. Our data model is OneRoster-shaped and the importer reads the standard CSV file set, but we have not been through 1EdTech certification and do not appear on their conformance list. If your procurement requires the certification mark, that is a genuine gap and we would rather you knew now.

One price. Every feature. Locked for three years.

$3.50 per student per year under 5,000 students. No tiers, no add-on modules, no per-message fees. Published on the site because you should not have to book a call to learn a price.