Documentation

The API

Version 0.1 ·Updated 2026-08-29

Next reviewed by 2027-02-28.

Written for integrators building against ataw without asking permission first.

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 Deprecation response 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.