For large districts: procurement thresholds, multiple systems of record, no appetite for surprises
Above about 10,000 students the evaluation stops being a product comparison and becomes a procurement process with a product attached. This page is written for the part of that process where somebody has to write the technical response.
| Level | Can read | Mechanism | What it is not |
|---|---|---|---|
| Another district | Nothing | Row-level security keyed on org, evaluated under a non-owner DML-only Postgres role | Not a WHERE clause the application remembers to add |
| District (parent org) | Itself and all child schools | Hierarchy-aware RLS policy | Not a UI filter |
| School (child org) | Itself only | Same policy, evaluated from the school's org context | Not role-based hiding of navigation |
| No org context set | Nothing — zero rows | Policies evaluate against NULL and fail closed | Not an error page; an empty result |
| Database owner connection | Blocked in CI | Owner-bypass regression test in the cross-tenant leakage suite | Not an assumption about how the app connects |
| API key | Its own org, subject to the same policies | Org-scoped key, SHA-256 hashed at rest, shown once | Not scope-limited for reads — see below |
| Audit log | Its own org's chain | Per-org SHA-256 chain, append-only at role and policy level | Not editable by us either |
The API row is a genuine gap and we would rather you read it here: scopes are enforced for send and SCIM operations only, so a non-revoked key can read org data regardless of the scope granted. Do not present scope-based read control to your security team as a Kastr control.
Multiple systems of record
Large districts rarely have one clean roster. They have a SIS, a special-education system, a nutrition system, a transport system and at least one building that maintains a spreadsheet, and the contact data in each disagrees.
Kastr's position is deliberately narrow: it consumes a roster POSTed to /api/v1/roster/sync and applies a diff with SHA-256 payload hashing, classifying every record as added, changed, unchanged or withdrawn. It does not attempt to reconcile your systems for you, and it does not have native connectors to PowerSchool, Infinite Campus, Skyward, Aeries or Synergy — none exist. In a district your size that is usually fine, because you already have an integration layer or a rostering intermediary and you would rather own the mapping than inherit a vendor's assumptions.
The guardrail that matters at scale: a sync that would withdraw more than half of active records aborts and is recorded as aborted_guardrail rather than applied. This is the defence against the failure mode that actually happens — a nightly export truncates, the file is valid, and a naive diff concludes that 60% of the district has left.
Being honest about the other half of that: withdrawal is recorded, but audience resolution does not yet consult enrolment status at send time. A withdrawn student's guardians are not automatically excluded from a send today. In a district of 20,000 with normal mobility, that is a real operational issue and it is at the top of our list.
What your purchasing office will ask for, and where it is
- Published price list. On the pricing page, no quote gate, per band.
- Master agreement with the four clauses. §3.2 price lock, §7.1 export right, §9.4 non-solicitation, §11.2 change-of-control exit.
- Data privacy agreement and sub-processor list. Stated plainly: our published sub-processor lists have been inconsistent across pages, and only Supabase, Resend and DeepL are actually wired into the running system. A DPA conversation should start from that, not from a longer aspirational list.
- Security questionnaire responses. The architecture table on the technology director page is written in questionnaire-answer language for exactly this reason.
- Accessibility documentation. We do not have a VPAT and we do not have automated accessibility testing in CI. For a public-school vendor that is a real gap, it will surface in your process, and we are not going to pretend it is scheduled when it is not yet done.
- Insurance certificates, SOC 2, references. Pre-launch. We have none of these.
If your purchasing policy makes SOC 2 or a VPAT mandatory, we fail your process this cycle. That is a straightforward answer and it saves both sides three months.
Cost at your bands
$3.25 per student from 5,000 to 14,999, $3.00 at 15,000 and above:
- 10,000 students: $32,500 a year, $97,500 across the locked 36 months.
- 14,500 students: $47,125 a year, $141,375 locked.
- 15,000 students: $45,000 a year — less than at 14,500, because the band changed. $135,000 locked.
- 20,000 students: $60,000 a year, $180,000 locked.
- 25,000 students: $75,000 a year, $225,000 locked.
At these figures the contract almost certainly exceeds your board's approval threshold, which means the five-year projection is the number that gets scrutinised rather than year one. §3.2 caps years four and five at the lesser of CPI-U or 5%, so a 20,000-student district's worst legal case is $63,000 and $66,150 in those years — $309,150 across five years. Model that against an uncapped alternative and the gap is the argument.
The API story for your data warehouse
28 org-scoped REST endpoints, all subject to the same row-level policies as the console. Signed outbound webhooks carry an HMAC-SHA256 signature computed over "${timestamp}.${rawBody}", pass through a DNS-resolving SSRF guard that rejects loopback, RFC1918 and link-local addresses after resolution, retry on a 1, 2, 5, 15, 60, 360-minute backoff, and auto-disable after ten consecutive failures. An MIT-licensed CLI and MCP server sit on top, in public, usable without our involvement.
Two limits to plan around. Rate limiting is in-memory and per Node process, so counters reset on restart and do not coordinate across instances — fine for a nightly extract, not something to build a tight ingestion loop against. And SCIM is beta: userName eq is the only supported filter, totalResults returns the page size, and there is no DELETE, no /Groups and no /ServiceProviderConfig, which will break a strict IdP's pagination.
No named competitor in K-12 communications publishes a district-facing REST API at all. That is the strongest thing we have to offer a district your size, and it is also the thing least likely to appear on a feature comparison grid.
Questions people actually ask
How does isolation work between schools inside one district?
Hierarchy-aware row-level security. A school's org context resolves only that school's rows; the district's context resolves itself and all child schools; nothing resolves a sibling district. It is enforced in Postgres under a non-owner, DML-only role inside every transaction, so it is not something the application can forget to apply, and an owner-bypass regression test runs in CI.
Do we need an RFP, and can you respond to one?
Whether you need one is set by your state and your board's threshold, and at these contract values it usually is required. We can respond, and the architecture answers are already published in questionnaire language so most of a technical response is copy-and-verify. What we cannot supply is a SOC 2 report, a VPAT, or customer references — if those are scored as mandatory, we will not clear your evaluation this cycle.
What is the API story for our data warehouse?
28 org-scoped REST endpoints under the same row-level policies as the console, plus signed webhooks with HMAC-SHA256 over timestamp and raw body, an SSRF guard that resolves DNS before checking, exponential backoff and automatic endpoint disable. Rate limiting is in-memory per process, so plan a scheduled extract rather than a tight loop.
What is the price above 15,000 students?
$3.00 per student per year, flat, with every feature included. A 20,000-student district is $60,000 a year and $180,000 across the locked 36-month term. Because the bands are flat rather than marginal, a district at 15,000 pays less in total than one at 14,500.
Can you support a district with multiple bell schedules and calendars?
Calendar-aware behaviour in Kastr means our release cadence, not per-school bell schedules: major releases land in May with PD packs and September to May is polish only. Quiet hours are configurable per organisation with a 21:00–07:00 default. Per-school academic calendars are not modelled, so if your messaging logic depends on differing term dates by campus, that is a gap worth testing before you commit.
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.