Documentation
The API
Read this first
ataw has no scoped API tokens yet, so you cannot build an unattended integration against it today. Every endpoint that serves school data is authenticated by a browser session. Scoped tokens are the next thing on this surface, and this page will change when they land.
The rest of this is published anyway, because deciding whether to integrate with a vendor is something you should be able to do before signing anything. A closed API is becoming disqualifying in this sector, and gating the reference behind a partner conversation is the same thing with better manners.
The reference is generated
The machine-readable reference is an OpenAPI document the server produces from its own route table. It is not maintained by hand, so it cannot drift from the routes it describes.
curl https://app.menta.seraco.io/_openapi.json
Point your generator at it. One caveat worth knowing: it also lists the framework's own internal routes, the ones under /__nuxt and /api/_nuxt_icon. They are not part of the API and are not supported. Everything else in the document is.
Two calls that work right now
Neither needs an account, which is what makes them useful for checking connectivity.
curl https://app.menta.seraco.io/health
{ "status": "healthy", "uptime": 1284, "version": "2026-08-29T04:11:00Z" }version is the build timestamp rather than the source revision: enough to tell one deployment from the next without naming the code it was cut from. The route answers while database migrations are still running, so a health check can distinguish "starting" from "broken".
curl https://app.menta.seraco.io/api/hello
Authentication
Sign-in is passwordless: a passkey, or a one-time code sent by email. It produces a session cookie, and that cookie is what every guarded endpoint checks. There is no password to send, and therefore no basic auth.
Every route that serves student data checks the session itself. The browser-side route guard exists to make navigation behave, and the access control lives on the server.
When scoped tokens arrive they will be issued per integration, carry a scope per record domain, be revocable individually, and appear in the audit log. Each one covers a single integration, so revoking it stops that integration and nothing else.
Errors
Every failure is JSON with the same shape. statusMessage is written for a person; data is for your code.
{
"statusCode": 422,
"statusMessage": "This palette was refused",
"data": { "failures": ["The accent on the page in light mode is 2.4:1, and needs 3:1."] }
}- 400
- The request was malformed, or a required field was missing. The message names the field.
- 401
- No session, or an expired one. Sign in again; do not retry the same request.
- 403
- Signed in, but not permitted. Retrying will not help.
- 404
- No such record, or no such route. It does not distinguish between them for records another school owns.
- 409
- Someone else changed the record since you read it. Re-read it, reapply your change, and send it again with the new version.
- 422
- The request was understood and the content was refused. `data` carries the specific reasons, one per failure, not just the first.
- 500
- Our fault. Safe to retry once, with a delay.
The distinction between 409 and 422 is the one worth internalising. A 409 means the record moved on and your change is probably still valid: re-read, reapply, resend. A 422 means the content itself was refused and resending it unchanged will be refused again.
Versioning and deprecation
The API is at 0.x and is not stable. While it is, an endpoint can change shape between releases, and this page will say so.
Once it reaches 1.0, three commitments hold:
- Adding a field to a response is not a breaking change. Write your client to ignore fields it does not know.
- Removing or renaming a field, or changing its type, means a new major version. Both versions run side by side for at least twelve months.
- A deprecation is announced on this page and in a
Deprecationresponse header before it takes effect, with the removal date stated in the announcement.
The questions you would ask next
Answered here, including where the answer is "not yet".
- How do I list the students changed since yesterday?
- You cannot yet. There is no student endpoint. When there is, it will take an `as at` parameter rather than a `since` cursor, because every fact in the record carries validity dates and the honest answer to "what changed" is a comparison of two dated snapshots.
- How do I push a result back?
- You cannot yet. Writes will carry the record version you read, and a write against a stale version is refused with a 409 rather than silently overwriting whoever got there first. That behaviour exists and is tested today on the endpoints that do accept writes.
- What happens when I retry?
- Reads are safe to retry. Writes are not idempotent yet, because there is no idempotency key, so a retried write after a timeout may apply twice. Treat a timed-out write as unknown and re-read before retrying.
- What are the rate limits?
- There are none. Read that as an absence rather than a promise of unlimited throughput. When a limit arrives it will be documented here first.
Pagination
Nothing paginates yet, because nothing returns a collection large enough to need it. When collections arrive they will be cursor-paginated rather than offset-paginated: a school's record changes while you are reading it, and offsets silently skip and duplicate rows when that happens.
Getting in touch
api@seraco.io. If you are building something and an endpoint you need is missing, that is worth telling us before you work around it.