Skip to content
Serelane

API

Every instance documents its own API.

The reference /docs/api on your instance
The document /api/v1/openapi.yaml on your instance

This page does not reproduce either, and that is deliberate: a reference rendered here would document whichever version last built this site, while the one on your instance documents the binary you are actually running. When they disagree, yours is right.

The document is hand-written, and a test asserts it matches the routes the router registers, so an endpoint added without documenting it fails the build.

These are stable across versions and worth knowing before you read the reference.

Two surfaces, split by who is calling. /api/v1/public/* serves the end users of a hosted app, who may be anonymous, so nothing there requires a session. /api/v1/admin/* serves the people running the instance and requires an admin session cookie.

Cookie sessions, not bearer tokens. HttpOnly and SameSite=Lax, with a server-side session record, so signing out and revoking actually work. Private boards can additionally issue bearer read tokens, which widen what may be read and nothing else.

Errors are RFC 9457 problem details, with the application/problem+json media type.

Lists are paginated by opaque cursor, not by offset. An offset silently skips or repeats rows when the underlying list changes between pages, which it constantly does on a board people are voting on.

Projects are addressed by slug on the public surface and by id on the admin surface. A slug is what a visitor’s URL carries and it can change; an id is stable and is what your tooling should hold. A renamed project answers its old slug with a 301 to the current one, so shared links keep working.

Public routes carry per-route budgets, keyed by identity first and hashed address second, and answer 429 with a Retry-After header when exceeded.

Reads get a deliberately generous budget, because the key is an address and an address is not a person: an office behind one NAT is many readers in one bucket. If your instance is behind a proxy, set SERELANE_TRUSTED_PROXIES or every caller shares a single bucket. See Configuration.