# API reference The full, searchable reference is the Integration page of the running app (`/integration`). It renders `web/src/data/apiCatalogue.ts`, which is the single source for this page. This file is for readers without the UI. ## Base URL The origin that serves the app, for example `https://cms.example`. Every path starts with `/v1`, for example `https://cms.example/v1/article/`. ## Authentication - Public routes need nothing: `GET /v1/article/` and `GET /v1/article/{id}`. They return online articles only. - Everything else needs a signed-in browser session (the `jwt` cookie) or an API key: `Authorization: Bearer rcms_...`. Create keys at `/integration/api-keys`. A key acts as its creator, with that user's role, and shows in full once. - A key cannot call `POST /v1/auth/verify`, `DELETE /v1/auth/register`, `/v1/api-key/*` or `/v1/system/*`. Those answer 403 "This action needs a real session." An invalid, unknown, expired or revoked key answers 401, even on public routes. - Each key can make 120 requests per minute. Beyond that: 429 with a `Retry-After` header. ## Routes a key can call (20) | Group | Routes | | --- | --- | | Articles | GET /v1/article/, GET /v1/article/{id}, POST /v1/article/, PATCH /v1/article/{id}, PATCH /v1/article/{id}/publish, PATCH /v1/article/{id}/unpublish, DELETE /v1/article/{id} | | Media | GET /v1/media/, POST /v1/media/, PATCH /v1/media/{id}, DELETE /v1/media/{id}, POST /v1/media/merge, GET /v1/media/{id}/usage | | Users and invites | GET /v1/user/, PATCH /v1/user/me, POST /v1/user/invite (owner only), DELETE /v1/user/invite/{id} (owner only), POST /v1/user/invite/{id}/renew (owner only), GET /v1/auth/me | | Settings | GET /v1/settings | ## Activity log The activity routes are session only: a key answers 403 "This action needs a real session." and a key never reads the audit trail. Events are append-only; there is no `POST`, `PUT`, `PATCH` or `DELETE` under `/v1/activity`. | Route | Who | Purpose | | --- | --- | --- | | `GET /v1/activity` | Any verified user | Filtered, paged events. Owner and admin see every event; any other role is scoped to its own events, and `actor` set to someone else answers 403 "Only owners and admins can do this." | | `GET /v1/activity/summary` | Owner, admin | Counts for the range, the previous period, active people and seven-bucket series. | | `GET /v1/activity/export` | Owner, admin | The same filters as the list without `page` or `size`, as a `text/csv; charset=utf-8` attachment (`when,actor,action,target,outcome,source,ip`). Cells starting with `=`, `+`, `-` or `@` get a leading quote. | Query: `q`, `actor` (`user:ID`, `key:ID`, `system`), `category` (`articles`, `media`, `users`, `api_keys`, `auth`, `system`), `outcome` (`all`, `success`, `failed`), `security` (`true`), `range` (`today`, `7d`, `30d`, `custom`; default `7d`), `from` and `to` (dates, with `custom`), `page` (from 1) and `size` (25, 50 or 100). Any invalid value answers 400 with the body-mismatch message. Dates are UTC. The list answers `{ items, total, page, size }`, newest first (`created_at`, then `id`). `GET /v1/settings` also returns `activity_retention_days` (30, 90, 365 or 0 for forever, default 90), `activity_last_cleanup_at` and `activity_last_cleanup_removed`. `PATCH /v1/settings` with `{"activity_retention_days": 30}` is session only and owner only (403 "Only the owner can do this."); any other value answers 400. Article routes accept `?format=markdown|html|json` (default `markdown`). `GET /v1/media/` accepts `q`, `hash`, `cursor`, `filter`, `sort` and `limit`. ## Errors Every error is a plain-text body with one sentence; the status is in the HTTP status line. The statuses are 400, 401, 403, 404, 409, 429 and 500. Messages are listed on the Integration page. ## Notes - Images in `body` use paths like `/static/uploadedImages/.png`. Prefix them with the base URL. - Browsers can call the API only from origins in the server's CORS setting.