Read this when adding or changing a versioned JSON API endpoint and its React caller. # Add or Change an API Endpoint 1. **Choose the authorization contract.** Classify the route as public, authenticated, role-protected, and/or state-changing. See [identity spec](../identity/spec.md). 2. **Register the route** in `src/OpenMind/Api/Api.php` using `AddRoute()` and the `/api/v1` path convention. ```php $this->AddRoute('GET /api/v1/example', __NAMESPACE__ . '\\ExampleController->index'); ``` 3. **Implement the controller** as a `Controller` subclass. Use `requireAuthentication()` / `requireRole()` first. For mutations, reject invalid CSRF before persistence. ```php if (!$this->requireRole(1)) return; if (!$this->validateCsrfToken()) { $this->sendError('Invalid CSRF token', 403); return; } ``` 4. **Validate JSON input** with `decodeJsonRequest()` and return only an explicit JSON DTO via `sendJson()`. Do not serialize mappers or return credential/configuration fields. 5. **Preserve persistence invariants.** Use parameterized mapper predicates; wrap serialized multi-step mutation checks in a transaction when needed. See [MySQL integration](../integrations/mysql.md). 6. **Add the frontend client call** to `ui/app/src/api/client.js` using `apiRequest()`. Do not bypass its base-path, cookie, JSON-error, or CSRF handling. 7. **Connect the UI and documentation.** Add/update the feature and route only when the server authorizes it, then update [API routes](../api-routes.md) and the relevant domain/integration spec. No automated test command is configured; review the method/path, authorization, CSRF, request validation, safe response shape, and affected frontend call before delivery.