The Users API provides control over user accounts in RomM. Most endpoints require admin-level access — creating users, changing roles, and generating invite links are restricted to users with theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/rommapp/romm/llms.txt
Use this file to discover all available pages before exploring further.
users.write scope. Every user can read and update their own profile via the /api/users/me and /api/users/{id} endpoints.
Roles
RomM uses a two-tier role model:| Role | Description |
|---|---|
admin | Full access. Bypasses all permission group checks. Can create, edit, and delete any user. |
user | Access is governed by their assigned permission group. Can only edit their own profile. |
The legacy
viewer and editor roles from older RomM versions are automatically coerced to user at login. There is no longer a separate editor tier — granular permissions are managed through permission groups.GET /api/users
Retrieve all user accounts. Admin-only. Required scope:users.read
UserSchema objects.
Internal user ID.
Username (lowercase).
Email address (lowercase).
Whether the account is active.
Role value:
admin or user.ID of the assigned permission group.
null uses the server default.Computed list of OAuth2 scopes the user can grant.
Path to the user’s avatar image.
ISO 8601 last login timestamp (UTC).
ISO 8601 last activity timestamp (UTC).
Linked RetroAchievements username.
RetroAchievements progression data.
User UI preference settings.
ISO 8601 creation timestamp.
ISO 8601 last-updated timestamp.
GET /api/users/identifiers
Retrieve only the IDs of all user accounts. Required scope:users.read
[1, 2, 3, ...]
GET /api/users/me
Retrieve the currently authenticated user’s profile. Also returns the currentdevice_id if a device session is active.
Required scope: me.read
UserSchema for the current user, with current_device_id populated.
GET /api/users/
Retrieve a single user by internal ID. Required scope:users.read
User internal ID.
UserSchema or 404 if not found.
GET /api/users//avatar
Serve a user’s avatar image. Any authenticated user can fetch any other user’s avatar (avatars are considered public within an authenticated session). Required scope:assets.read
User internal ID.
POST /api/users
Create a new user account. Requires admin privileges (theusers.write scope) when admin users already exist. During initial setup (no admins exist yet) this endpoint is open.
Required scope: users.write (once any admin exists)
Username for the new account (must be unique).
Email address (must be unique).
Initial password.
Role for the new user:
admin or user. Only an existing admin can create another admin.201 Created — the new UserSchema.
PUT /api/users/
Update a user account. Acceptsmultipart/form-data so that a new avatar can be uploaded in the same request.
Admins can update any user. Non-admin users can only update themselves.
Required scope: me.write (self) or users.write (admin updating another user)
User internal ID.
DELETE /api/users/
Delete a user account. Removes the user’s avatar directory from disk. Required scope:users.write
User internal ID.
204 No Content.
| Guard | Error |
|---|---|
| Deleting yourself | 400 You cannot delete yourself |
| Deleting the last admin | 400 You cannot delete the last admin user |
POST /api/users/invite-link
Generate an invite link token that allows someone to self-register with a pre-assigned role. Only admins can generate admin invite links. Required scope:users.write
Role for the invited user:
admin or user.Token lifetime in seconds. Defaults to
INVITE_TOKEN_EXPIRY_SECONDS. Must be a positive integer.POST /api/users/register.
POST /api/users/register
Self-register using an invite link token. No authentication required.New username.
Email address.
Password.
Invite token received from an admin.
201 Created — the new UserSchema.
POST /api/users//ra/refresh
Refresh RetroAchievements progression data for a user. Requires the user to havera_username set.
Required scope: me.write
User internal ID.
When
true, only retrieves new progression since the last refresh. When false, fetches the full progression from scratch.200 OK (no body).