List org users
GET/api/users
Authentication: bearer token.
Permission: users.view.
curl -X GET "https://shellius.example.com/api/users" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Own preferences
GET/api/users/me/preferences
Authentication: bearer token.
Permission: any signed-in user.
curl -X GET "https://shellius.example.com/api/users/me/preferences" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Update own preferences
PUT/api/users/me/preferences
Authentication: bearer token.
Permission: any signed-in user.
Request body
| Name | Type | Required | Notes |
|---|---|---|---|
emailNotifications | boolean | No | |
expiringSoonAlerts | boolean | No |
curl -X PUT "https://shellius.example.com/api/users/me/preferences" \
-H "Authorization: Bearer $SHELLIUS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"emailNotifications": false,
"expiringSoonAlerts": false
}'200 OK
{ "success": true, "data": { … } }Own full profile
GET/api/users/me
Return the calling user's full profile.
Authentication: bearer token.
Permission: any signed-in user.
curl -X GET "https://shellius.example.com/api/users/me" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Update own name
PUT/api/users/me
Update name only (NOT email, role, or other fields)
Authentication: bearer token.
Permission: any signed-in user.
Request body
| Name | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | 1–255 characters. |
curl -X PUT "https://shellius.example.com/api/users/me" \
-H "Authorization: Bearer $SHELLIUS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "…"
}'200 OK
{ "success": true, "data": { … } }Upload own avatar
PUT/api/users/me/avatar
Upload a custom avatar (strict Joi + server-side decode validation in userService/utils/avatar.js). DELETE removes it.
Authentication: bearer token.
Permission: any signed-in user.
Request body
| Name | Type | Required | Notes |
|---|---|---|---|
dataUrl | string | Yes | At most 300000 characters. |
curl -X PUT "https://shellius.example.com/api/users/me/avatar" \
-H "Authorization: Bearer $SHELLIUS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"dataUrl": "…"
}'200 OK
{ "success": true, "data": { … } }Remove own avatar
DELETE/api/users/me/avatar
Authentication: bearer token.
Permission: any signed-in user.
curl -X DELETE "https://shellius.example.com/api/users/me/avatar" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Change own password
PUT/api/users/me/password
Change password (LOCAL users only)
Authentication: bearer token.
Permission: any signed-in user.
Rate limit: 5 requests per 15 minutes per IP address.
Request body
| Name | Type | Required | Notes |
|---|---|---|---|
currentPassword | string | Yes | |
newPassword | string | Yes | At least 12 characters. |
curl -X PUT "https://shellius.example.com/api/users/me/password" \
-H "Authorization: Bearer $SHELLIUS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"currentPassword": "…",
"newPassword": "…"
}'200 OK
{ "success": true, "data": { … } }GDPR export of own data
GET/api/users/me/export
GDPR data export.
Authentication: bearer token.
Permission: any signed-in user.
curl -X GET "https://shellius.example.com/api/users/me/export" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"Returns a file or plain text, not the JSON envelope.
Soft-delete own account
DELETE/api/users/me
Soft-delete account.
Authentication: bearer token.
Permission: any signed-in user.
curl -X DELETE "https://shellius.example.com/api/users/me" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Get user
GET/api/users/:id
Authentication: bearer token.
Permission: any signed-in user; some behaviour depends on users.view, users.view_reports.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X GET "https://shellius.example.com/api/users/{id}" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Create user / send invite
POST/api/users
Create user; optionally send invite when no password supplied.
Authentication: bearer token.
Permission: users.invite.
Request body
| Name | Type | Required | Notes |
|---|---|---|---|
email | string | Yes | An email address. |
name | string | Yes | 1–200 characters. |
password | string | No | 8–200 characters. |
roleId | string | No | At most 100 characters. |
role | string | No | At most 100 characters. |
managerId | string | No | May be null. |
sendInvite | boolean | No | Default true. |
accessScope | string | No | One of ALL, CUSTOMERS. |
customerIds | array | No | Default []. |
groupIds | array | No |
curl -X POST "https://shellius.example.com/api/users" \
-H "Authorization: Bearer $SHELLIUS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "…",
"name": "…"
}'201 Created
{ "success": true, "data": { … } }Update user
PUT/api/users/:id
Authentication: bearer token.
Permission: any signed-in user.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Request body
| Name | Type | Required | Notes |
|---|---|---|---|
email | string | No | An email address. |
name | string | No | 1–200 characters. |
roleId | string | No | At most 100 characters. |
role | string | No | At most 100 characters. |
status | string | No | |
managerId | string | No | May be null. |
groupIds | array | No |
curl -X PUT "https://shellius.example.com/api/users/{id}" \
-H "Authorization: Bearer $SHELLIUS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "…",
"name": "…",
"roleId": "…"
}'200 OK
{ "success": true, "data": { … } }Scope
PUT/api/users/:id/scope
Set accessScope + the UserCustomerScope rows (docs/rbac/customer-scope-spec.md). All the interesting rules (self, out-of-scope grants, org membership) live in the service.
Authentication: bearer token.
Permission: users.assign_scope.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Request body
| Name | Type | Required | Notes |
|---|---|---|---|
accessScope | string | Yes | One of ALL, CUSTOMERS. |
customerIds | array | No | Default []. |
curl -X PUT "https://shellius.example.com/api/users/{id}/scope" \
-H "Authorization: Bearer $SHELLIUS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accessScope": "ALL"
}'200 OK
{ "success": true, "data": { … } }Effective scope
GET/api/users/:id/effective-scope
Explains WHY, for the "effective access" UI (docs/rbac/customer-scope-spec.md §7 phase 4, §2 groups decision).
Authentication: bearer token.
Permission: users.view.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X GET "https://shellius.example.com/api/users/{id}/effective-scope" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Preview user hard-delete impact
GET/api/users/:id/delete-impact
Authentication: bearer token.
Permission: users.delete.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X GET "https://shellius.example.com/api/users/{id}/delete-impact" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Hard-delete user
DELETE/api/users/:id
Authentication: bearer token.
Permission: users.delete.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X DELETE "https://shellius.example.com/api/users/{id}" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Set user's SSH public key
PUT/api/users/:id/ssh-key
Authentication: bearer token.
Permission: any signed-in user; some behaviour depends on users.update.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Request body
| Name | Type | Required | Notes |
|---|---|---|---|
publicKey | string | Yes |
curl -X PUT "https://shellius.example.com/api/users/{id}/ssh-key" \
-H "Authorization: Bearer $SHELLIUS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"publicKey": "…"
}'200 OK
{ "success": true, "data": { … } }Remove user's SSH public key
DELETE/api/users/:id/ssh-key
Authentication: bearer token.
Permission: any signed-in user; some behaviour depends on users.update.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X DELETE "https://shellius.example.com/api/users/{id}/ssh-key" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }List direct reports of a user
GET/api/users/:id/reports
Authentication: bearer token.
Permission: any signed-in user; some behaviour depends on users.view_reports, users.view.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X GET "https://shellius.example.com/api/users/{id}/reports" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Re-issue INVITE token + email
POST/api/users/:id/resend-invite
Revoke previous invite and re-issue.
Authentication: bearer token.
Permission: users.invite.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X POST "https://shellius.example.com/api/users/{id}/resend-invite" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Admin-issued password reset link
POST/api/users/:id/password-reset
Issue a 1-hour reset token for a user.
Authentication: bearer token.
Permission: users.reset_credentials.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X POST "https://shellius.example.com/api/users/{id}/password-reset" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Identities
GET/api/users/:id/identities
Sign-in methods — GET /:id/identities, DELETE /:id/identities/:identityId (users.manage_identities). Same no-escalation rule as managing the user (roleService.canActOnRole), and the last way to sign in can't be removed. Unlinks are audited (auth.identity.unlinked, method: admin) and the user is emailed.
Authentication: bearer token.
Permission: users.manage_identities.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X GET "https://shellius.example.com/api/users/{id}/identities" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Delete user
DELETE/api/users/:id/identities/:identityId
Authentication: bearer token.
Permission: users.manage_identities.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string | |
identityId | string |
curl -X DELETE "https://shellius.example.com/api/users/{id}/identities/{identityId}" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Clear login lockout
POST/api/users/:id/unlock
Clears a lockout (failedLoginCount/lockedUntil)
Authentication: bearer token.
Permission: users.reset_credentials.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X POST "https://shellius.example.com/api/users/{id}/unlock" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }Sign user out everywhere
POST/api/users/:id/revoke-sessions
Revokes every session + bumps sessionsValidFrom so all of the user's outstanding access tokens die too.
Authentication: bearer token.
Permission: users.revoke_sessions.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
curl -X POST "https://shellius.example.com/api/users/{id}/revoke-sessions" \
-H "Authorization: Bearer $SHELLIUS_TOKEN"200 OK
{ "success": true, "data": { … } }