Skip to content

Working with roles

Roles are self-managed groups whose membership can change as users join or leave them.

Roles can be added to group chats as members. When a user joins a role, they immediately gain access to all chats the role participates in.

This guide shows how to inspect roles in the directory, use them as chat members, read the sender roles stored on messages, and react to role events.

Checking whether roles are enabled

Role features are controlled by the organization. Check roles_enabled before offering role-specific operations:

from teamwire_api import Connection

async def print_role_status(connection):
    permissions = await connection.get_permissions()
    print(f'Roles enabled: {permissions.roles_enabled}')

with Connection() as connection:
    connection.exec_async(print_role_status(connection))

When roles_enabled is False, applications should not try to list roles or use them as chat members.

Listing visible roles

The role directory is available through connection.roles. The get_list() coroutine returns the current non-deleted roles visible to the bot:

from teamwire_api import Connection

async def list_roles(connection):
    permissions = await connection.get_permissions()
    if not permissions.roles_enabled:
        print('Roles are not enabled for this organization')
        return

    roles = await connection.roles.get_list()
    for role in roles:
        organization = role.organisation.name if role.organisation else 'unknown'
        print(
            f'{role.name or "unnamed"}: '
            f'id={role.id}, visibility={role.visibility}, '
            f'organization={organization}'
        )

with Connection() as connection:
    connection.exec_async(list_roles(connection))

Role IDs should be used when storing references or accepting role input. Role names are intended for display and are not stable identifiers.

To retrieve one role by ID, use connection.roles.get_role(role_id). The SDK raises TWNotFoundError if the role is not visible or does not exist.

Listing the users in a role

Role.get_members() resolves the role's current member IDs to SDK User objects. It is a coroutine because resolving users may require directory access:

async def print_role_members(role):
    users = await role.get_members()
    print(f'Members of {role.name or role.id}:')
    for user in users:
        print(f'- {user.full_name()} ({user.uid})')

Users who are deleted or not visible to the bot are omitted from the returned list.

Inspecting roles in a chat

A Chat exposes its direct role members through get_role_members():

async def print_chat_roles(connection, thread_id):
    chat = await connection.chats.get_by_thread_id(thread_id)
    if chat is None:
        print('Chat not found')
        return

    for role in chat.get_role_members():
        print(f'- {role.name or "unnamed"} ({role.id})')

This returns Role objects, not the individual users currently represented by those roles. Use await role.get_members() when the expanded user list is needed.

Creating a chat with roles

Roles can be passed alongside direct users and public circles when creating a group chat:

from teamwire_api import Connection

async def create_role_chat(connection):
    permissions = await connection.get_permissions()
    if not permissions.roles_enabled:
        print('Roles are not enabled for this organization')
        return

    role = await connection.roles.get_role('ROLE_ID')
    chat = await connection.chats.create_chat(
        title='Operations',
        roles=[role],
        message='Welcome to the operations chat'
    )
    print(f'Created chat {chat.tid}')

with Connection() as connection:
    connection.exec_async(create_role_chat(connection))

Roles can only be used with group chats. They cannot be recipients of a 1:1 chat.

Adding and removing role members from a chat

Chat administrators can update role membership with the same methods used for users and circles:

async def update_chat_role(connection, thread_id, role_id):
    permissions = await connection.get_permissions()
    if not permissions.roles_enabled:
        print('Roles are not enabled for this organization')
        return

    chat = await connection.chats.get_by_thread_id(thread_id)
    role = await connection.roles.get_role(role_id)

    await chat.add_members(roles=[role])
    print(f'Added {role.name or role.id}')

    await chat.remove_members(roles=[role])
    print(f'Removed {role.name or role.id}')

These operations require permission to edit chat members and are not supported for 1:1 chats.

Reading a message sender's roles

Messages can contain the names of the roles held by the sender when the message was sent. They are exposed through Message.sender_roles:

from teamwire_api import Connection, Events

def message_handler(event_type, message):
    print(f'From: {message.from_user.full_name()}')
    if message.sender_roles:
        print(f'Sender roles: {", ".join(message.sender_roles)}')

with Connection() as connection:
    connection.set_handler([Events.NEW_MESSAGE], message_handler)
    connection.start_notifications()

sender_roles is a list of role names, not Role objects. It is message metadata frozen at send time, so it may differ from the sender's current role membership and does not require a role-directory lookup.

Role changes affecting a chat are available through the notifications API. A ChatMemberChangeInfo event payload can include affected roles, users, the chat, and the user who performed the change in editor:

from teamwire_api import Connection, Events

ROLE_EVENTS = [
    Events.CHAT_MEMBERS_ADDED,
    Events.CHAT_MEMBERS_REMOVED,
    Events.ROLES_JOINED,
    Events.ROLES_LEFT,
    Events.ROLE_USERS_REMOVED,
    Events.ROLES_DELETED,
]

def role_event_handler(event_type, info):
    role_names = [role.name or role.id for role in info.roles]
    user_names = [user.full_name() for user in info.users]
    print(f'{event_type.value} in chat {info.chat.tid}')
    print(f'Roles: {", ".join(role_names) or "none"}')
    print(f'Users: {", ".join(user_names) or "none"}')

with Connection() as connection:
    connection.set_handler(ROLE_EVENTS, role_event_handler)
    connection.start_notifications()

CHAT_MEMBERS_ADDED and CHAT_MEMBERS_REMOVED report roles added to or removed from a chat. The other events describe users joining or leaving chat roles, users being removed from a role, and roles being deleted.