Your district's data is not locked behind a chatbot.
The most useful thing AI brings to a school district is not a bot bolted onto a dashboard — it is clean, governed, logged access to the data and the actions. So everything in Kastr is available three ways: a REST API, a CLI and a native MCP server, under your keys, your row-level security and your audit log.
| Resource | Routes | What it is for |
|---|---|---|
| People | /people | Search students, guardians and staff. One person row carries many effective-dated roles, so a search for a teacher who is also a parent returns one result, not two. |
| Broadcasts | /broadcasts | Create and send. Audience is everyone or an explicit list of person ids; selecting a student expands to that student's guardians. |
| Audiences | /audiences | Reusable saved selections, so a nightly script can send to the same cohort without rebuilding it. |
| Roster | /roster/sync, /roster/runs, /roster/sources | POST roster data, then inspect the diff: added, changed, unchanged, withdrawn, with a SHA-256 payload hash per run. |
| Forms | /forms, /forms/{id}, /forms/{id}/responses | Publish a form and pull responses as JSON rather than a CSV download. |
| Groups | /groups, /groups/{id}, /groups/{id}/members, /groups/{id}/posts | Community group membership and posts, including group-identity posts that still record the real author for audit. |
| Webhooks | /webhooks, /webhooks/{id}, /webhooks/run | Register outbound endpoints, inspect deliveries, force a retry. |
| Operations | /health, /me, /tasks, /templates, /insights, /data-health, /dispatch/run | Key introspection, the worklist, message templates, delivery records, and a manual dispatch tick for local development. |
A key can only ever touch its own district: every request runs inside a transaction under a non-owner, DML-only Postgres role with app.current_org_id set, and a policy that evaluates against NULL returns zero rows. That behaviour is regression-tested in CI against a real Postgres 16, including an owner-bypass check.
Three faces, one API
The CLI and the MCP server are not separate products with their own data paths. They are clients of the same 28 endpoints the console uses, which means there is exactly one place where authorisation, rate limiting and audit logging happen.
- REST API. Search families, POST a roster, send a broadcast, pull form responses — the same operations a logged-in administrator performs, behind one bearer key. Org-scoped and row-level-security enforced.
- CLI. 16 commands, MIT licensed.
kastr people,kastr health,kastr send. Drop it in a cron job or a CI step, pipe the JSON anywhere. There is no SDK to be locked into; it is the API underneath. - MCP server. 19 typed tools for any MCP client —
search_people,list_data_health,send_broadcast— gated by your key, with sends held for human approval.
No named competitor in K-12 family communication ships a public district-facing API at all. Integration is a partner programme you apply to. If your team wants to script a bulk operation at 11pm on a Sunday, that difference is the whole thing.
A key, a base URL, done
Mint a scoped key in the admin console. It is shown exactly once and stored as a SHA-256 hash, so a database leak does not hand anyone a working credential.
Two details worth knowing before you build against it. Broadcast audiences are either everyone or an explicit list of person ids — the API returns a 400 for grade, school, class, language or route presets rather than silently resolving them to every guardian in the district. And rate limits are returned in standard X-RateLimit-* headers with Retry-After on a 429, though the current implementation is per-process and in-memory, so treat the headers as advisory rather than as a cluster-wide guarantee.
Hand it to an agent
Add Kastr to any MCP client and "which families have we not reached this week, and draft an SMS to them" becomes a real workflow rather than a demo. The tools are typed, the key scopes the district, and the send is held for a human.
This is deliberately the opposite architecture to an in-product assistant. A chatbot you cannot audit is a liability in a district: it sits inside the vendor's trust boundary, runs on a model you did not choose, and leaves you reading a transcript rather than a log. Governed, key-scoped, logged access compounds instead — your team, your scripts and whatever model you already trust, all working from one source of truth.
Signed webhooks, and the SSRF problem nobody mentions
Outbound webhooks carry X-Kastr-Signature: sha256=<hmac> computed over "${timestamp}.${rawBody}", the same construction Stripe uses, so a receiver can verify authenticity and reject replays without trusting the transport.
The less obvious half is inbound safety. A district administrator can type any URL into a webhook field, and an unguarded delivery worker will happily fetch http://169.254.169.254/ for them. Every destination is DNS-resolved before delivery and rejected if it lands on loopback, RFC1918 or link-local space. Failures retry on a [1, 2, 5, 15, 60, 360]-minute backoff and the endpoint auto-disables after ten consecutive failures, so one dead receiver does not become a queue that never drains.
Roster connector configuration applies the same suspicion in the other direction: a config containing what looks like a literal credential — sk_, whsec_, AKIA, AIza, ghp_, xoxb-, -----BEGIN — is rejected outright. You supply a reference to a secret, not the secret.
The security model the API runs inside
Every request runs inside a transaction that sets a non-owner, DML-only Postgres role and an app.current_org_id. Row-level security is therefore enforced against a role that cannot bypass it through table ownership — the classic way RLS quietly stops working. Isolation is hierarchy-aware: a district sees its own rows and its child schools' rows, never another district's. With no org id set, policies evaluate against NULL and return zero rows, so the failure mode is an empty result rather than a leak.
The audit log is a per-organisation SHA-256 hash chain where each entry commits to the previous one, serialised under an advisory transaction lock so it stays correct under concurrency, and append-only at two independent layers: UPDATE and DELETE are revoked at the grant level, and the RLS policy set has no update or delete policy to fall back on. A cross-tenant leakage suite runs in CI against real Postgres 16, including a regression check for the owner-bypass case.
What we are not claiming. There is no SSO, SAML, OIDC or MFA — magic link is the only authentication in the product. API keys are not read-scoped, so treat every live key as a full-read credential for its district and rotate on staff changes. Rate limiting is per-process rather than cluster-wide. And we have no SOC 2 report. Those are the four things a security reviewer would find, so they are on the page rather than in a follow-up email.
Questions people actually ask
Is the Kastr API included in the price or a separate tier?
Included. There is one tier at each enrolment band and the API, the CLI and the MCP server are part of it. An API access tier is on the published list of things we will not sell, because charging for the interface to your own data is a portability tax with a better name.
What can the MCP server actually do?
19 typed tools over the same endpoints the console uses: searching people, listing the worklist, reading delivery records, drafting and sending broadcasts. Sends are held for human approval rather than executed by the model. It runs under your API key, which means the district scope, the row-level security and the audit trail are identical to a human session.
How do we get roster data in without a native SIS connector?
POST it to /api/v1/roster/sync in the documented shape, on whatever schedule suits you. The diff engine hashes each payload with SHA-256 and classifies every record as added, changed, unchanged or withdrawn, and a guardrail aborts the run with aborted_guardrail if it would withdraw more than half your active records — the truncated-export failure that turns one bad file into a district-wide messaging outage. There are no vendor-branded connectors that fetch from PowerSchool or Infinite Campus for you today.
Can an API key from one district read another district's data?
No, and the enforcement is at the database rather than in application code. Requests run under a non-owner Postgres role with the org id set as a session variable, so row-level security cannot be bypassed through table ownership, and a request with no org id set returns zero rows rather than everything. The cross-tenant leakage suite runs in CI against real Postgres 16 with an explicit owner-bypass regression test.
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.