# API Reference All endpoints are under `/api/`. JSON in, JSON out. Auth via session cookie + remember-me. ## Auth ### `POST /api/login` ```json { "email": "...", "password": "..." } ``` Returns `{ ok, email, name }` or `401`. ### `POST /api/logout` Invalidates session. Returns `{ ok: true }`. ### `GET /api/me` Returns `{ ok, email, id, name, locale, is_admin }` or `{ ok: false }` (401) if not logged in. ### `PATCH /api/me` ```json { "name": "Max" } ``` Updates display name. Returns `{ ok, name }`. ```json { "locale": "de" } ``` Updates UI language (`de`, `en`, `pl`). Returns `{ ok, locale }`. ### `POST /api/register` ```json { "email": "...", "password": "...", "token": "", "name": "..." } ``` Requires a valid pending invite token. Registers + auto-logs in. Returns `{ ok, email, name }`. ### `POST /api/reset-request` ```json { "email": "..." } ``` Sends password reset mail. Always returns `{ ok: true }` (no email enumeration). ### `POST /api/reset-password` ```json { "selector": "...", "token": "...", "password": "..." } ``` ### `POST /api/change-password` ```json { "old_password": "...", "new_password": "..." } ``` --- ## Goals ### `GET /api/goals` Returns array of goal objects for the authenticated user. ```json [{ "id": "1", "name": "Liegestütz", "unit": "Stück", "daily": 50, "days": 30, "start": "2026-04-01 00:00:00", "sets": { "2026-04-01": [20, 30], "2026-04-02": [50] } }] ``` `sets` is a JSON object keyed by date (`YYYY-MM-DD`), values are arrays of logged amounts. ### `POST /api/goals` ```json { "name": "...", "unit": "Stück", "daily": 50, "days": 30, "start": "2026-04-01" } ``` ### `PATCH /api/goals/{id}` Partial update — send only fields to change: `name`, `unit`, `daily`, `days`, `sets`. ### `DELETE /api/goals/{id}` Deletes goal. Only owner can delete. --- ## Invites ### `POST /api/invite` ```json { "note": "Max" } ``` Creates a 7-day single-use invite token. Returns `{ url: "http://dudi.local/?invite=" }`. ### `GET /api/invites` Returns all invites created by the authenticated user. ```json [{ "url": "http://dudi.local/?invite=...", // null if used or expired "note": "Max", "status": "pending", // "pending" | "used" | "expired" "created_at": "...", "expires_at": "...", "used_at": null, "used_by_email": null }] ``` --- ## Admin ### `GET /api/admin/users` Returns all users. Only accessible if the logged-in user's email matches `ADMIN_EMAIL` env var; returns `403` otherwise. ```json [{ "id": 1, "email": "user@example.com", "username": "Max", "registered": 1714500000 }] ```