/api
Eternaltwin exposes its data over an HTTP+JSON API mounted at /api.
Only one version exists today.
- v1 — the current API.
- Internal endpoints — routes served by the same process but
outside
/api: the backend-for-frontend, the OAuth browser flow and the OpenTelemetry collectors.
Conventions
- Every response body is JSON, encoded as UTF-8.
- Field names are
snake_case, exactly as they are spelled in the Rust types ofcrates/core. They are not converted tocamelCase. - Tagged objects carry their own
"type"discriminant ("User","ForumThread","OauthClient", …). - Timestamps are ISO 8601 in UTC with millisecond precision, e.g.
"2021-01-15T14:17:14.015Z". - Identifiers are UUIDs, serialized as lowercase hyphenated strings.
- A paginated response is a listing:
{
"offset": 0,
"limit": 20,
"count": 137,
"items": []
}
count is the total number of matching items, not the length of items.
- An error response is
{"error": "<message>"}with a 4xx or 5xx status. A few endpoints answer with a richer object instead; those say so on their own page.
Authenticating a request
The API accepts three kinds of credentials, checked in this order:
Authorization: Basic <base64(login:password)>— Eternaltwin credentials.Authorization: Bearer <access_token>— an OAuth access token.Cookie: sid=<session_id>— the browser session cookie set byPUT /api/v1/auth/selfandPOST /api/v1/users.
Whatever is used, the request ends up with an auth context: see /api/v1/auth/self for its exact shape. Credentials that cannot be resolved normally degrade to a guest context rather than failing, so a read never breaks on a stale cookie; endpoints that write reject an unresolvable credential with 401 instead.
Some endpoints are reserved for the server itself and require the
Etwin-Internal-Auth header rather than a user credential. They are marked as
such on their page.