Skip to content

Users

albert.collections.users.UserCollection

UserCollection(*, session: AlbertSession)

Bases: BaseCollection

Manage Users in the Albert platform.

A User is an Albert user account: a person who can log in and act in the platform. Each user has a name and email, a set of Role objects that govern what they can do, an optional home Location, and an ACL class level (UserClass) that sets a broad permission tier.

Users are grouped into teams (see TeamCollection), and are referenced throughout the platform: Tasks can be assigned to a user, and entities carry ACLs that reference users and their roles. A user is identified by its User ID (format USR..., e.g. "USR12").

This collection is accessed as client.users.

Example

from albert import Albert
client = Albert()
# Look up the signed-in user, then find others at the same location
me = client.users.get_current_user()
colleagues = client.users.get_all(max_items=25)
for user in colleagues:
    print(user.id, user.name, user.email)

Parameters:

Name Type Description Default
session AlbertSession

The authenticated Albert session used for API calls.

required

Attributes:

Name Type Description
base_path str

The base API route for user requests.

Methods:

Name Description
get_current_user

Get the user account for the currently authenticated session.

get_by_id

Get a single fully populated user by its ID.

search

Fast, lightweight search returning partial users (best for lookups).

get_all

Same idea as search, but returns fully populated users (slower).

create

Create a new user account.

update

Update an existing user.

Parameters:

Name Type Description Default
session AlbertSession

The authenticated Albert session used for API calls.

required
Source code in src/albert/collections/users.py
def __init__(self, *, session: AlbertSession):
    """Initialize a UserCollection.

    Parameters
    ----------
    session : AlbertSession
        The authenticated Albert session used for API calls.
    """
    super().__init__(session=session)
    self.base_path = f"/api/{UserCollection._api_version}/users"

base_path

base_path = f'/api/{UserCollection._api_version}/users'

get_current_user

get_current_user() -> User

Get the user account for the currently authenticated session.

Use this to find out who the active credentials belong to, for example to set yourself as the assignee of a Task or to check your own roles.

Example

me = client.users.get_current_user()
me.name
# 'Ada Lovelace'

Returns:

Type Description
User

The fully populated user for the authenticated session.

Source code in src/albert/collections/users.py
def get_current_user(self) -> User:
    """Get the user account for the currently authenticated session.

    Use this to find out who the active credentials belong to, for example
    to set yourself as the assignee of a Task or to check your own roles.

    !!! example
        ```python
        me = client.users.get_current_user()
        me.name
        # 'Ada Lovelace'
        ```

    Returns
    -------
    User
        The fully populated user for the authenticated session.
    """
    response = self.session.get(
        "/api/v3/login/validatejwt",
        params={"includeUserDetails": True},
    )
    payload = response.json()
    user_id = payload.get("userId")
    if not user_id:
        raise ValueError("Current user lookup failed.")
    return self.get_by_id(id=user_id)

get_by_id

get_by_id(*, id: UserId) -> User

Get a single, fully populated user by its ID.

To find users without knowing their IDs, use search or get_all.

Example

user = client.users.get_by_id(id="USR12")
user.email
# 'ada@example.com'

Parameters:

Name Type Description Default
id UserId

The User ID (format USR..., e.g. "USR12").

required

Returns:

Type Description
User

The fully populated user.

Source code in src/albert/collections/users.py
@validate_call
def get_by_id(self, *, id: UserId) -> User:
    """Get a single, fully populated user by its ID.

    To find users without knowing their IDs, use [`search`][albert.collections.users.UserCollection.search] or
    [`get_all`][albert.collections.users.UserCollection.get_all].

    !!! example
        ```python
        user = client.users.get_by_id(id="USR12")
        user.email
        # 'ada@example.com'
        ```

    Parameters
    ----------
    id : UserId
        The User ID (format ``USR...``, e.g. ``"USR12"``).

    Returns
    -------
    User
        The fully populated user.
    """
    url = f"{self.base_path}/{id}"
    response = self.session.get(url)
    return User(**response.json())

search

search(
    *,
    text: str | None = None,
    sort_by: str | None = None,
    order_by: OrderBy = DESCENDING,
    roles: list[str] | None = None,
    teams: list[str] | None = None,
    locations: list[str] | None = None,
    status: list[Status] | None = None,
    user_id: list[UserId] | None = None,
    subscription: list[str] | None = None,
    search_fields: list[str] | None = None,
    facet_text: str | None = None,
    facet_field: str | None = None,
    contains_field: list[str] | None = None,
    contains_text: list[str] | None = None,
    mentions: bool | None = None,
    additional_field: list[str] | None = None,
    custom_fields: dict[str, Any] | None = None,
    metadata_filters: dict[str, Any] | None = None,
    source_field: list[str] | None = None,
    witnesser: list[str] | None = None,
    offset: int = 0,
    max_items: int | None = None,
) -> Iterator[UserSearchItem]

Search for users matching the given filters.

This returns lightweight, partial results (UserSearchItem) and is the fastest way to look users up by name, role, team, or location. For fully populated User entities, use get_all, or call hydrate() on a search item.

Example

# Find users whose name or email mentions "ada"
for user in client.users.search(text="ada", max_items=10):
    print(user.id, user.name)

Parameters:

Name Type Description Default
text str

Free-text search across multiple user fields (e.g. name, email).

None
sort_by str

Field to sort results by.

None
order_by OrderBy

Sort direction, ascending or descending. Defaults to descending.

DESCENDING
roles list[str]

Restrict to users holding any of these role names.

None
teams list[str]

Restrict to members of any of these teams.

None
locations list[str]

Restrict to users at any of these location IDs.

None
status list[Status]

Restrict to users with any of these statuses (e.g. active, inactive).

None
user_id list[UserId]

Restrict to these specific User IDs.

None
subscription list[str]

Restrict to users with any of these subscription types.

None
search_fields list[str]

The fields that text is matched against.

None
facet_text str

Text to match within a facet, used together with facet_field.

None
facet_field str

The facet field that facet_text is applied to.

None
contains_field list[str]

Field names to apply "contains" filtering on, paired positionally with contains_text.

None
contains_text list[str]

Substrings to match within the corresponding contains_field.

None
mentions bool

When True, restrict to users who are mentioned.

None
additional_field list[str]

Request additional columns from the search index.

None
custom_fields dict[str, Any]

Filter by custom field values.

None
metadata_filters dict[str, Any]

Filter by custom field (metadata) values.

None
source_field list[str]

Restrict which fields are returned in the response.

None
witnesser list[str]

Filter by witnesser status.

None
max_items int

Maximum total number of users to return. If None, returns all matches.

None

Returns:

Type Description
Iterator[UserSearchItem]

An iterator of partial users matching the filters.

Source code in src/albert/collections/users.py
@validate_call
def search(
    self,
    *,
    text: str | None = None,
    sort_by: str | None = None,
    order_by: OrderBy = OrderBy.DESCENDING,
    roles: list[str] | None = None,
    teams: list[str] | None = None,
    locations: list[str] | None = None,
    status: list[Status] | None = None,
    user_id: list[UserId] | None = None,
    subscription: list[str] | None = None,
    search_fields: list[str] | None = None,
    facet_text: str | None = None,
    facet_field: str | None = None,
    contains_field: list[str] | None = None,
    contains_text: list[str] | None = None,
    mentions: bool | None = None,
    additional_field: list[str] | None = None,
    custom_fields: dict[str, Any] | None = None,
    metadata_filters: dict[str, Any] | None = None,
    source_field: list[str] | None = None,
    witnesser: list[str] | None = None,
    offset: int = 0,
    max_items: int | None = None,
) -> Iterator[UserSearchItem]:
    """Search for users matching the given filters.

    This returns lightweight, partial results ([`UserSearchItem`][albert.resources.users.UserSearchItem]) and
    is the fastest way to look users up by name, role, team, or location.
    For fully populated [`User`][albert.resources.users.User] entities, use [`get_all`][albert.collections.users.UserCollection.get_all], or call
    `hydrate()` on a search item.

    !!! example
        ```python
        # Find users whose name or email mentions "ada"
        for user in client.users.search(text="ada", max_items=10):
            print(user.id, user.name)
        ```

    Parameters
    ----------
    text : str, optional
        Free-text search across multiple user fields (e.g. name, email).
    sort_by : str, optional
        Field to sort results by.
    order_by : OrderBy, optional
        Sort direction, ascending or descending. Defaults to descending.
    roles : list[str], optional
        Restrict to users holding any of these role names.
    teams : list[str], optional
        Restrict to members of any of these teams.
    locations : list[str], optional
        Restrict to users at any of these location IDs.
    status : list[Status], optional
        Restrict to users with any of these statuses (e.g. active, inactive).
    user_id : list[UserId], optional
        Restrict to these specific User IDs.
    subscription : list[str], optional
        Restrict to users with any of these subscription types.
    search_fields : list[str], optional
        The fields that ``text`` is matched against.
    facet_text : str, optional
        Text to match within a facet, used together with ``facet_field``.
    facet_field : str, optional
        The facet field that ``facet_text`` is applied to.
    contains_field : list[str], optional
        Field names to apply "contains" filtering on, paired positionally
        with ``contains_text``.
    contains_text : list[str], optional
        Substrings to match within the corresponding ``contains_field``.
    mentions : bool, optional
        When True, restrict to users who are mentioned.
    additional_field : list[str], optional
        Request additional columns from the search index.
    custom_fields : dict[str, Any], optional
        Filter by custom field values.
    metadata_filters : dict[str, Any], optional
        Filter by custom field (metadata) values.
    source_field : list[str], optional
        Restrict which fields are returned in the response.
    witnesser : list[str], optional
        Filter by witnesser status.
    max_items : int, optional
        Maximum total number of users to return. If None, returns all
        matches.

    Returns
    -------
    Iterator[UserSearchItem]
        An iterator of partial users matching the filters.
    """
    params = {
        "text": text,
        "sortBy": sort_by,
        "order": order_by,
        "roles": roles,
        "teams": teams,
        "locations": locations,
        "status": status,
        "userId": user_id,
        "subscription": subscription,
        "searchFields": search_fields,
        "facetText": facet_text,
        "facetField": facet_field,
        "containsField": contains_field,
        "containsText": contains_text,
        "mentions": mentions,
        "additionalField": additional_field,
        "sourceField": source_field,
        "witnesser": witnesser,
        "offset": offset,
    }

    deserialize = lambda items: [
        UserSearchItem(**item)._bind_collection(self) for item in items
    ]

    payload: dict[str, Any] = {**params}
    if metadata_filters is not None:
        payload["metadataFilters"] = {"metadata": metadata_filters}
    if custom_fields is not None:
        payload["customFields"] = {"metadata": custom_fields}

    return AlbertPaginator(
        mode=PaginationMode.OFFSET,
        path=f"{self.base_path}/search",
        session=self.session,
        max_items=max_items,
        deserialize=deserialize,
        method="POST",
        json=payload,
    )

get_all

get_all(
    *,
    status: Status | None = None,
    type: UserFilterType | None = None,
    id: list[UserId] | None = None,
    start_key: str | None = None,
    max_items: int | None = None,
) -> Iterator[User]

Get fully populated users, with optional filters.

Each result is fetched individually via get_by_id, so this is convenient but slower than search. Prefer search when you only need lightweight, partial results.

Example

from albert.core.shared.enums import Status
active_users = client.users.get_all(status=Status.ACTIVE, max_items=50)
for user in active_users:
    print(user.name)

Parameters:

Name Type Description Default
status Status

Restrict to users with this status (e.g. active, inactive).

None
type UserFilterType

The attribute that id filters on. Currently only role is supported.

None
id list[UserId]

The values to filter on for the chosen type (e.g. role IDs when type is role).

None
start_key str

Pagination cursor marking where the next page of results begins.

None
max_items int

Maximum total number of users to return. If None, returns all matches.

None

Returns:

Type Description
Iterator[User]

An iterator of fully populated users. Preserves has_more / total from the underlying list paginator.

Source code in src/albert/collections/users.py
@validate_call
def get_all(
    self,
    *,
    status: Status | None = None,
    type: UserFilterType | None = None,
    id: list[UserId] | None = None,
    start_key: str | None = None,
    max_items: int | None = None,
) -> Iterator[User]:
    """Get fully populated users, with optional filters.

    Each result is fetched individually via [`get_by_id`][albert.collections.users.UserCollection.get_by_id], so this is
    convenient but slower than [`search`][albert.collections.users.UserCollection.search]. Prefer [`search`][albert.collections.users.UserCollection.search] when
    you only need lightweight, partial results.

    !!! example
        ```python
        from albert.core.shared.enums import Status
        active_users = client.users.get_all(status=Status.ACTIVE, max_items=50)
        for user in active_users:
            print(user.name)
        ```

    Parameters
    ----------
    status : Status, optional
        Restrict to users with this status (e.g. active, inactive).
    type : UserFilterType, optional
        The attribute that ``id`` filters on. Currently only ``role`` is
        supported.
    id : list[UserId], optional
        The values to filter on for the chosen ``type`` (e.g. role IDs when
        ``type`` is ``role``).
    start_key : str, optional
        Pagination cursor marking where the next page of results begins.
    max_items : int, optional
        Maximum total number of users to return. If None, returns all
        matches.

    Returns
    -------
    Iterator[User]
        An iterator of fully populated users. Preserves ``has_more`` / ``total``
        from the underlying list paginator.
    """
    params = {
        "status": status,
        "type": type,
        "id": id,
        "startKey": start_key,
    }

    def _hydrate(item: dict) -> User | None:
        user_id = item.get("albertId")
        if not user_id:
            return None
        try:
            return self.get_by_id(id=user_id)
        except AlbertHTTPError as e:
            logger.warning(f"Error fetching user '{user_id}': {e}")
            return None

    return MappedPaginator(
        AlbertPaginator(
            mode=PaginationMode.KEY,
            path=self.base_path,
            session=self.session,
            params=params,
            max_items=max_items,
            deserialize=lambda items: items,
        ),
        _hydrate,
    )

create

create(*, user: User) -> User

Create a new user account.

Example

from albert.resources.users import User, UserClass
new_user = User(
    name="Ada Lovelace",
    email="ada@example.com",
    user_class=UserClass.STANDARD,
)
created = client.users.create(user=new_user)
created.id
# 'USR12'

Parameters:

Name Type Description Default
user User

The user to create. name is required; set email, roles, location, and user_class as needed.

required

Returns:

Type Description
User

The newly created user, populated with its assigned User ID.

Source code in src/albert/collections/users.py
def create(self, *, user: User) -> User:  # pragma: no cover
    """Create a new user account.

    !!! example
        ```python
        from albert.resources.users import User, UserClass
        new_user = User(
            name="Ada Lovelace",
            email="ada@example.com",
            user_class=UserClass.STANDARD,
        )
        created = client.users.create(user=new_user)
        created.id
        # 'USR12'
        ```

    Parameters
    ----------
    user : User
        The user to create. ``name`` is required; set ``email``, ``roles``,
        ``location``, and ``user_class`` as needed.

    Returns
    -------
    User
        The newly created user, populated with its assigned User ID.
    """

    response = self.session.post(
        self.base_path,
        json=user.model_dump(by_alias=True, exclude_none=True, mode="json"),
    )
    return User(**response.json())

update

update(*, user: User) -> User

Update an existing user.

Fetch the user (e.g. via get_by_id), modify the updatable fields, then pass it here. Only the fields listed in Notes are applied; changes to other fields are ignored.

Example

user = client.users.get_by_id(id="USR12")
user.name = "Ada King"
updated = client.users.update(user=user)
updated.name
# 'Ada King'

Parameters:

Name Type Description Default
user User

The user with desired changes applied. Must carry a valid id.

required

Returns:

Type Description
User

The updated user.

Notes

The following fields can be updated: email, metadata, name, status.

Source code in src/albert/collections/users.py
def update(self, *, user: User) -> User:
    """Update an existing user.

    Fetch the user (e.g. via [`get_by_id`][albert.collections.users.UserCollection.get_by_id]), modify the updatable
    fields, then pass it here. Only the fields listed in Notes are applied;
    changes to other fields are ignored.

    !!! example
        ```python
        user = client.users.get_by_id(id="USR12")
        user.name = "Ada King"
        updated = client.users.update(user=user)
        updated.name
        # 'Ada King'
        ```

    Parameters
    ----------
    user : User
        The user with desired changes applied. Must carry a valid ``id``.

    Returns
    -------
    User
        The updated user.

    Notes
    -----
    The following fields can be updated: ``email``, ``metadata``, ``name``,
    ``status``.
    """
    # Fetch the current object state from the server or database
    current_object = self.get_by_id(id=user.id)

    # Generate the PATCH payload
    payload = self._generate_patch_payload(existing=current_object, updated=user)

    url = f"{self.base_path}/{user.id}"
    self.session.patch(url, json=payload.model_dump(mode="json", by_alias=True))

    updated_user = self.get_by_id(id=user.id)
    return updated_user