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 can read OneRoster 1.1 and 1.2 REST rosters and preview uploaded OneRoster CSV ZIP files. An organisation administrator configures the connection under Integrations, OneRoster. REST sync can run nightly after the first manual apply when the production worker is configured for that organisation. The custom JSON roster API and typed roster CSV import remain separate routes. A standards-based connection does not establish a vendor partnership or certification. For a multi-school deployment, verify tenant boundaries and the configured worker scope rather than assuming every customer is scheduled.
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.
The other half of that: people a sync withdraws are treated as retired, and audience resolution filters out suppressed and retired people at send time, so they are left out of later sends without anyone editing an audience.
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. Supabase, Resend and DeepL are wired into the running system, and so is SMS through Bandwidth, switched on per school once it is set up. 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. Independently operated. 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.
Plan integrations around the published rate limits, enforced across instances by atomic Postgres counters. 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 limits use atomic Postgres counters shared across instances. Plan extracts around the published request budgets.
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 or add-on modules. Normal messaging is included under a published fair-use allowance, with transparent cost recovery only above it.