How to sync PowerSchool SIS with Kastr
There is no Kastr plugin in the PowerSchool marketplace and no PowerSchool connector in Kastr. What there is: an export you almost certainly already run, one scheduled POST, and a diff engine that shows you the damage before it happens. The interesting part of a PowerSchool sync is not the plumbing, it is ENROLL_STATUS and the week in July when your schools roll.
| Value | PowerSchool meaning | Kastr roster state | Include in the export? | Can this person be messaged? |
|---|---|---|---|---|
0 | Actively enrolled | Active | Yes | Yes |
-1 | Pre-registered / pre-enrolled | Pre-enrolled | Yes, deliberately | Yes — this is your August welcome audience |
-2 | Inactive | Withdrawn | Only if you want the withdrawal recorded | Should not be |
2 | Transferred out of district | Withdrawn | Only for the withdrawal signal | Should not be |
3 | Graduated / historical | Historical | No | No |
4 | Imported historical record | Ignored | No | No |
Districts customise status codes, so confirm yours against your own Students table rather than trusting this list. The rule that matters: pick one filter and keep it stable. Changing the filter between two nightly runs is indistinguishable, to a diff engine, from thousands of students withdrawing overnight.
Getting the data out: three routes
Data Export Manager, scheduled. The path most districts take. Build a student export and a contacts export, schedule both nightly, drop them to an SFTP location you control. Effort is a few hours, most of it deciding which contact fields you want. This is the route we recommend for a first sync because everything is visible and nothing is magic.
A saved PowerQuery pulled by your own job. If your team is comfortable with PowerQueries and the PowerSchool API, you can have a district-side script pull the query result and pipe it straight into the Kastr CLI without touching disk. Fewer moving parts, more code to own.
PowerSchool's OneRoster output through a broker. If you already run Clever or ClassLink against PowerSchool, that feed is already normalised and you should use it — with one caveat that costs districts a fortnight: guardian phone numbers are frequently not in the broker share, which leaves you with a roster that cannot send SMS or voice. Check the guardian fields before you commit to that route.
Whichever you choose, the last hop is the same: POST /api/v1/roster/sync, with --dry-run until the numbers reconcile.
Contacts, not the legacy parent fields
PowerSchool's modern Contacts model replaced the old Mother, Father and Guardian columns on the student record, and a lot of district exports still read the legacy fields because that is what the script did in 2015. Those columns are frequently stale, frequently blank, and cannot express a third adult or a custody restriction.
Export from Contacts. The fields worth carrying, and what each becomes:
- Contact record and relationship type → the guardian-to-student edge, with the relationship stored as given. Kastr does not try to normalise "Stepmother" into a canonical vocabulary; it keeps what you sent.
- Emergency priority / contact order → contact rank. Rank 1 is who a front-office staff member sees first, and it is what an escalating voice call walks down.
- Custody or guardianship flag → carried onto the edge. This is the field that decides whether an adult should receive anything at all, and it is worth auditing before your first send rather than after.
- "Receives mail" / correspondence flags → folded into
consentStateon the resulting contact points. - Phone type → a mobile number becomes an SMS-capable contact point; a landline becomes voice-only. Getting this wrong is how districts end up texting a work switchboard.
Every contact point in Kastr carries four things: the value, a validationState, a consentState for 10DLC and TCPA purposes, and a source. Source matters because a number the guardian typed into their own profile should outrank a number that has been sitting in the SIS since third grade, and a rank that ignores provenance is how you end up calling a disconnected line first.
The July rollover, and why it is the dangerous night
Every PowerSchool district has one week in July where schools roll, grade levels increment, next-year enrolments activate and last year's seniors go historical. Depending on how your export filter is written, the file produced during that window can be missing most of your district.
Two specific patterns cause it. First, an export filtered on the current school year runs before the year rolls and returns almost nothing. Second, an export filtered on ENROLL_STATUS = 0 runs after schools roll but before enrolments activate, and returns the same almost-nothing.
What happens in Kastr: the run computes that accepting the file would withdraw more than half of active records, refuses, records aborted_guardrail, and leaves yesterday's roster in place. In a 12,000-student district that is the difference between an aborted job and 9,000 families quietly detached from their students.
What to do about it: pause the nightly job for rollover week, run it manually with --dry-run when the SIS work is finished, read the ledger, then resume. Ten minutes of deliberate work instead of a September of confusion.
Every run — including the aborted ones — is written to a per-organisation, append-only audit log whose entries are chained with SHA-256, so the record of what happened on rollover night is not something anyone can quietly tidy up afterwards.
One human, one record
PowerSchool districts hit this constantly: a parent with children at three schools, a teacher who is also a parent at the building where she teaches, a paraprofessional who is a guardian for a niece. Systems that key identity on enrolment produce three, four, five copies of the same adult, and every one of them gets its own text message.
Kastr stores one person and attaches effective-dated roles. She is a guardian at the middle school from August 2024, a teacher at the elementary from August 2019, and both facts are true simultaneously without duplication. Selecting a student in the composer auto-expands to their guardians, and the expansion de-duplicates, so a family with two children in the same broadcast gets one message rather than two.
Be aware of the current limit: audiences resolve as specific named people or as everyone. Grade-level and school-level targeting are modelled in the roster but not yet resolved by the audience engine. If your workflow is "message everyone at Lincoln Middle", today that is a saved audience preset built once, not a filter you pick at send time.
Questions people actually ask
Does Kastr have a native PowerSchool plugin in the marketplace?
No. There is no Kastr plugin, no PowerSchool partnership, and no Kastr code that authenticates to PowerSchool. You produce an export — Data Export Manager, a PowerQuery, or a broker's OneRoster feed — and a district-side job POSTs it to our roster endpoint. Anyone claiming a deeper integration in this category is usually describing a partner listing.
Which PowerSchool ENROLL_STATUS values should I include in the export?
Include 0 for active students, and include -1 for pre-registered students if you want to message incoming families before the year starts, which most districts do in August. Exclude graduated and imported historical records entirely. Confirm the codes against your own instance, since districts customise them, and then keep the filter stable — changing it between runs looks exactly like a mass withdrawal to a diff engine.
How do I get guardian mobile numbers out of PowerSchool Contacts rather than the legacy fields?
Build the contacts export from the Contacts model rather than the Mother, Father and Guardian columns on the student record. Carry relationship type, contact order, custody flag, correspondence flag, phone number and phone type. The phone type is the field that decides whether Kastr treats a number as SMS-capable or voice-only, so exporting it saves you from texting landlines.
What happens to messages queued for a student who was withdrawn overnight?
Straight answer: the roster records the withdrawal, but the send path does not yet filter on enrolment state, so a queued or subsequently composed message to a saved audience containing that family can still go out. Suppression at send time is the most consequential gap we have and it is on the near-term list. Until it ships, withdrawal handling is a roster change plus an audience change.
Can Kastr write attendance or message logs back into PowerSchool?
No. There is no write-back path of any kind. PowerSchool stays the system of record and Kastr never modifies it. If you want message history alongside SIS data, pull it from our REST API into your warehouse rather than expecting it to appear in PowerSchool.
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.