Skip to content

API Reference

The backend exposes a versioned REST API under /api/v2. All responses are reactive JSON. Every call requires a bearer JWT except the four public authentication endpoints. Project-scoped endpoints live under /api/v2/projects/{projectId}/… and are guarded by a project-scoped permission — often combined with an option gate when the resource belongs to an optional module.

The v2 contract follows the conventions in ADR 017: every state transition is its own POST endpoint (one endpoint, one functional action, no toggle-by-body and no value-in-path), pickers are named eligibility sub-collections searched with ?q=, and lists share one query grammar. v1 (/api/v1) is frozen and deprecated — its responses carry Deprecation/Sunset headers and it is removed once this frontend is fully cut over.

Notation. The Permission column names the authority required. hasAuthority('X') denotes a global permission; a bare project permission (e.g. MOVEMENT_C) denotes a project-scoped check hasPermission(projectId, 'REGISTRY_PROJECT_MOVEMENT_C'). Option marks endpoints additionally gated by a project option. See Security for enforcement and Roles & Permissions for who holds each.

List query grammar. Every collection accepts page (0-based) + size (bounded 1–200), sort=field,-otherField (leading - = descending), flat filter params (?status=ACCEPTED), and free-text ?q= (trigram-backed). JSON bodies and query params are camelCase.

When the backend runs with API docs enabled, an interactive OpenAPI/Swagger UI is served with the same security scheme (OAuth2) and grouped by the domains below.

Authentication — /api/v2/authentication

MethodPathPurposePermission
GET/login/uri?redirectUri=Build the provider login URLpublic
GET/logout/uri?redirectUri=Build the provider logout URLpublic
POST/tokenExchange an authorization code for tokenspublic
POST/token/refreshRefresh tokenspublic
GET/user/currentCurrent user, authorities and preferencesauthenticated

Users — /api/v2/users (global)

MethodPathPurposePermission
GET/?q=&page=&size=&sort=Search / list usersREGISTRY_USER_R
GET/{id}Get a userREGISTRY_USER_R
GET/rolesAssignable user rolesREGISTRY_USER_METADATA_R
PATCH/{id}/roleChange a user's global role (body: role)REGISTRY_USER_U
POST/{id}/block · /{id}/unblockBlock / unblock an accountREGISTRY_USER_U
POST/{id}/anonymizeAnonymize (GDPR purge) another userREGISTRY_USER_D
POST/anonymizeAnonymize the caller's own accountauthenticated
DELETE/{id}Delete a userREGISTRY_USER_D

v1 → v2: PATCH …/blockPOST …/block; PATCH …/unblockPOST …/unblock; PATCH …/impersonatePOST …/anonymize (renamed for accuracy — it never was impersonation); PATCH /impersonatePOST /anonymize.

Preferences — /api/v2/users/preferences (self)

MethodPathPurposePermission
POST/themeSet theme (body: themeSYSTEM/LIGHT/DARK)authenticated
POST/languageSet language (body: languageen/fr)authenticated
POST/select-profileSelect the active profile (body: exactly one of profileId | projectId)authenticated

v1 → v2: the two selectors (/profile/select by id and /projects/{projectId}/profile/select by project) collapse into one action — select the active profile — whose body carries either identifier.

My profiles — /api/v2/users/profiles (self)

MethodPathPurposePermission
GET/?page=&size=List the caller's project profilesauthenticated
POST/{id}/accept · /{id}/rejectAccept / reject an invitation (from INVITED)authenticated
POST/{projectId}/supportCreate a 1-hour support administrator profileREGISTRY_PROFILE_C
DELETE/{id}Leave a project (blocked if last administrator)authenticated

v1 → v2: POST /{id}/accept/{accepted} (boolean in path) splits into two explicit actions — POST /{id}/accept and POST /{id}/reject.

Projects — /api/v2/projects

MethodPathPurposePermission
GET/?q=&page=&size=&sort=List projects visible to the callerauthenticated
GET/{id}Get a projectREGISTRY_PROJECT_R (global or scoped)
GET/optionsAvailable option modulesREGISTRY_PROJECT_METADATA_R
POST/Create a project (creator becomes admin)REGISTRY_PROJECT_C
PATCH/{id}Update a projectPROJECT_U
POST/{id}/disable · /{id}/enableDisable / enable (soft)PROJECT_U
DELETE/{id}Delete a projectPROJECT_D

Project profiles (membership) — /api/v2/projects/{projectId}/profiles

MethodPathPurposePermission
GET/ · /{id}List / get membersPROFILE_R
GET/assignable-users?q=Search users assignable to this projectPROFILE_METADATA_R
GET/rolesAssignable project rolesPROFILE_METADATA_R
POST/Invite one or more usersPROFILE_C
PATCH/{id}Update role / access windowPROFILE_U
POST/{id}/block · /{id}/unblockBlock / unblock a memberPROFILE_U
DELETE/{id}Remove a memberPROFILE_D

v1 → v2: GET …/search/usersGET …/assignable-users?q=; PATCH …/block·/unblockPOST …/block·/unblock.

Participants — /api/v2/projects/{projectId}/participants

MethodPathPurposePermission
GET/ · /{id}List / get participantsPARTICIPANT_R
GET/birthdaysToday's birthdaysPARTICIPANT_R
GET/linkable-users?q= · /linkable-groups?q=Search users / groups linkable to a participantPARTICIPANT_METADATA_R
GET/{id}/movementsA participant's movement historyPARTICIPANT_HISTORY_R
POST/Create a participantPARTICIPANT_C
PATCH/{id}UpdatePARTICIPANT_U
POST/{id}/disable · /{id}/enableDisable / enablePARTICIPANT_U
DELETE/{id}Delete a participantPARTICIPANT_D

v1 → v2: GET …/search/users·/search/groupslinkable-users·linkable-groups; /birthday/birthdays; PATCH …/disable·/enablePOST verbs.

Groups — /api/v2/projects/{projectId}/groups

MethodPathPurposePermission
GET/ · /{id} · /{id}/membersList / get / list membersGROUP_R
GET/assignable-participants?q=Search participants addable to a groupGROUP_METADATA_R
POST/Create a groupGROUP_C
PATCH/{id}UpdateGROUP_U
POST/{id}/membersAdd members (body: participantIds)GROUP_U
DELETE/{id}/members/{memberId}Remove a memberGROUP_U
POST/{id}/disable · /{id}/enableDisable / enableGROUP_U
DELETE/{id}Delete a groupGROUP_D

v1 → v2: GET …/search/participants/assignable-participants?q=; adding members becomes POST …/members (was PATCH …/members); PATCH …/disable·/enablePOST verbs.

Movements — /api/v2/projects/{projectId}/movements

MethodPathPurposePermission
GET/ · /contents · /{id}List / list with content / getMOVEMENT_R
GET/reasons?q= · /eligible-participants-and-groups?q= · /eligible-vehicles?q=Pickers for the movement formMOVEMENT_METADATA_R
GET/participants/statusLive participant headcountREGISTRY_PROJECT_R
GET/vehicles/statusLive vehicle presenceREGISTRY_PROJECT_R · option VEHICLE
GET/{id}/communicationsMovement discussion threadMOVEMENT_COMMUNICATION_R · option COMMUNICATION
POST/ · /guestsRecord a movement / a guest movementMOVEMENT_C
PATCH/{id} · /guests/{id}Update / update guest movementMOVEMENT_U
POST/{id}/disable · /{id}/enableDisable / enableMOVEMENT_U
DELETE/{id}Delete a movementMOVEMENT_D

v1 → v2: GET …/search/reasons·/search/participants-and-groups·/search/vehicles/reasons·/eligible-participants-and-groups·/eligible-vehicles (each ?q=); PATCH …/disable·/enablePOST verbs.

Vehicles — /api/v2/projects/{projectId}/vehicles · option VEHICLE

MethodPathPurposePermission
GET/ · /{id}List / get vehiclesVEHICLE_R
GET/{id}/movementsA vehicle's movement historyVEHICLE_HISTORY_R
POST/Create a vehicleVEHICLE_C
PATCH/{id}UpdateVEHICLE_U
POST/{id}/disable · /{id}/enableDisable / enableVEHICLE_U
DELETE/{id}Delete a vehicleVEHICLE_D

Activities — /api/v2/projects/{projectId}/activities · option ACTIVITY

MethodPathPurposePermission
GET/ · /{id}List / get activitiesACTIVITY_R
GET/{id}/movementsAn activity's movement historyACTIVITY_HISTORY_R
POST/Create an activityACTIVITY_C
PATCH/{id}UpdateACTIVITY_U
POST/{id}/disable · /{id}/enableDisable / enableACTIVITY_U
DELETE/{id}Delete an activityACTIVITY_D

Communications — /api/v2/projects/{projectId}/communications · option COMMUNICATION

MethodPathPurposePermission
GET/ · /{id}List / get communicationsCOMMUNICATION_R
GET/attachable-movements?q= · /attachable-alerts?q=Pickers to attach a messageCOMMUNICATION_METADATA_R
POST/Post a messageCOMMUNICATION_C
PATCH/{id}UpdateCOMMUNICATION_U
POST/{id}/disable · /{id}/enableDisable / enableCOMMUNICATION_U
DELETE/{id}Delete a messageCOMMUNICATION_D

v1 → v2: GET …/search/movements·/search/alerts/attachable-movements·/attachable-alerts (each ?q=); PATCH …/disable·/enablePOST verbs.

Alerts — /api/v2/projects/{projectId}/alerts · option ALERT

MethodPathPurposePermission
GET/ · /{id}List / get alertsALERT_R
GET/{id}/communicationsAlert discussion threadALERT_COMMUNICATION_R
POST/Raise an alertALERT_C
PATCH/{id}UpdateALERT_U
POST/{id}/resolve · /{id}/cancel · /{id}/reopenStatus transitions (IN_PROGRESSRESOLVED/CANCELED)ALERT_U
POST/{id}/disable · /{id}/enableDisable / enableALERT_U
DELETE/{id}Delete an alertALERT_D

v1 → v2: PATCH …/status/{status} (enum in path) splits into one verb per transition — POST …/resolve, POST …/cancel, POST …/reopen; PATCH …/disable·/enablePOST verbs.

Metadata — /api/v2/metadata

Localized label lookups for the frontend (presences/status, availabilities/status, profiles/status, movements/types, participants/types, alerts/status). Authenticated; no special permission.

Purge (scheduled jobs) — /api/v2/purge

MethodPathPurposePermission
POST/users · /projects · /projects/contents · /projects/configurationsData-retention purgesREGISTRY_JOB_C

These are invoked by the system's SERVICE_ACCOUNT on a cron schedule; a platform administrator also holds REGISTRY_JOB_C.

Deprecated — /api/v1

The v1 contract remains available, frozen, during the migration. Every v1 response carries Deprecation: true, a Sunset date, and a Link to this reference (RFC 8594). v1 is removed once the Nuxt frontend is fully cut over in production and v1 traffic reaches zero — see ADR 017.