Users, Roles & Permissions
This guide covers the practical side of access control: listing users, assigning roles on an entity, checking what a user can actually do, and handling invitations. For the model behind it — the four layers that decide every request — read the Permissions concept first, and see The User and The Team for those entities' object references.
Users live under /users/v1; effective-permission checks live under
/entitypermissions/v1. Both are scoped.
List and read users
curl "https://api.lexabit.com/users/v1?perPage=25" \
-H "Authorization: Bearer $LEXABIT_TOKEN" -H "X-Scope: 42"
GET /users/v1/{id} returns one user, including their membership and roles
on the current scope:
{
"data": {
"id": "u-3391-…",
"name": "Ola Hansen",
"email": "ola@firm.no",
"roles": [ { "key": "case_editor", "name": "Case Editor" } ],
"membership": { "scopeType": "tenant", "scopeId": "2f5a9c1e-…" }
},
"meta": { "requestId": "d4e2…" }
}
Assign a role
Roles are granted per entity/scope — the same user can be an editor here and
a viewer there. Assign one with its role_key:
- curl
- Python
- JavaScript
curl -X POST "https://api.lexabit.com/users/v1/u-3391-…/roles" \
-H "Authorization: Bearer $LEXABIT_TOKEN" \
-H "X-Scope: 42" \
-H "Content-Type: application/json" \
-d '{ "role_key": "case_editor" }'
import os, requests
resp = requests.post(
"https://api.lexabit.com/users/v1/u-3391-…/roles",
headers={
"Authorization": f"Bearer {os.environ['LEXABIT_TOKEN']}",
"X-Scope": "42",
},
json={"role_key": "case_editor"},
)
resp.raise_for_status()
user = resp.json()["data"] # returns the updated user with roles[]
const resp = await fetch("https://api.lexabit.com/users/v1/u-3391-…/roles", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LEXABIT_TOKEN}`,
"X-Scope": "42",
"Content-Type": "application/json",
},
body: JSON.stringify({ role_key: "case_editor" }),
});
const user = (await resp.json()).data;
The role applies on the entity named by X-Scope. Remove a role with DELETE /users/v1/{id}/roles/{roleKey}.
Assigning roles is itself permission-gated: you can't grant a capability your own
role doesn't include. Attempting to escalate returns 403 forbidden.
Check what a user can actually do
Rather than assign a role and hope, ask the API for a user's effective permissions on a specific entity — the resolved answer after all four layers:
curl "https://api.lexabit.com/entitypermissions/v1/entities/case/c-4410-…/users/u-3391-…/effective-permissions" \
-H "Authorization: Bearer $LEXABIT_TOKEN" -H "X-Scope: 42"
This is the authoritative "would this action be allowed?" check — use it to drive UI (hide buttons a user can't use) instead of trial-and-error calls.
Scope profile
A user's per-scope profile (display fields specific to a scope) is read and updated with:
GET /users/v1/{id}/scope-profile
PUT /users/v1/{id}/scope-profile
Invitations
Invitations let people join an entity. The inviting side uses the shared
entity sub-resource (POST /entitymanagement/v1/{entityType}/{entityId}/invitations
— see Entities). The
invited user manages their own invitations under /users/v1/me:
# What am I invited to?
curl "https://api.lexabit.com/users/v1/me/invitations" \
-H "Authorization: Bearer $LEXABIT_TOKEN"
# Accept
curl -X POST "https://api.lexabit.com/users/v1/me/invitations/{token}/accept" \
-H "Authorization: Bearer $LEXABIT_TOKEN"
/decline rejects it. These me endpoints act on the authenticated user, so
they don't need an X-Scope.
Where to go next
- Permissions concept — the four-layer model and
the
403vs404distinction - Working with Clients & Cases — the entities these roles apply to
- API Reference → Access & Permissions