API Versioning
The HTTP API carries its own major version, negotiated per request with the
accept-version header. A client pinned to a version keeps getting that version’s
behaviour after a newer one ships, so an API change never forces an app update.
This version is not the application version. VERSION and MIN_VERSION track
releases of Skol Arena itself; a release can ship without touching the API contract,
and an API major can land while every client stays where it is.
Supported versions
| Version | Status |
|---|---|
v1 |
Current |
Negotiating a version
Send accept-version on every request:
curl -H 'accept-version: v1' https://your-instance/api/disciplines
The server answers with the version it actually resolved:
X-API-VERSION: v1
Vary: accept-version
Rules:
- No header → the latest version. Convenient for exploring, risky for an application: the day a new major ships, an unpinned client moves with it.
v1,V1or1→ all resolve tov1. Surrounding whitespace is ignored.- An unknown version →
400withUNSUPPORTED_API_VERSION, listing what is available. An empty header is treated the same way: it is a client bug, not a request for the latest.
{
"error": {
"code": "UNSUPPORTED_API_VERSION",
"message": "Unsupported API version \"v9\". Available versions: v1.",
"details": { "requested": "v9", "supported": "v1" }
}
}
The version never appears in a URL. Paths stay /api/… whatever version is in play.
Endpoints outside versioning
Three subtrees are not version-negotiated and ignore accept-version:
| Path | Why |
|---|---|
/api/auth/* |
Owned by Better Auth, which follows its own compatibility policy. |
/api/ws |
The browser WebSocket API cannot send request headers, so no client could negotiate. |
/api/docs, /api/openapi/* |
They describe the versions rather than living inside one. |
Errors
Every failure uses the same envelope. code is a stable identifier — the same
failure carries the same code in every language — while message is that code
rendered in the language asked for via Accept-Language.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation error",
"details": { "target": "json", "issues": [{ "path": "code", "message": "…" }] }
}
}
Reference documentation
Each version publishes an OpenAPI 3.1 document, generated from the same schemas the server validates against, so the reference cannot drift from the implementation:
GET /api/openapi/v1.json
An interactive Scalar reference is served at /api/docs, with
a version switcher and a “Try it” console that sends the right accept-version for
you.
Both are enabled in development and disabled when NODE_ENV=production. Set
API_DOCS_ENABLED=true to publish them from a production instance, or false to
switch them off anywhere.