Run your workspace
Members & roles
A workspace can have many members, each with a role. A role decides what a member can change β agents, knowledge, live chats, billing, other members β and which settings areas they can open. On top of the four built-in roles, a workspace can define its own roles with exactly the permissions it wants (Settings βΊ Roles). This page covers roles and permissions, the invitation flow, and what changes when a member is added, moved or removed.
What every member can do
Every member of a workspace can read its agents, conversations, leads, tickets, knowledge and analytics, whatever their role. Permissions only decide what they can change. A role with no permissions at all is a read-only role.
Permissions
There are 19 permissions, grouped by area. Each one is all-or-nothing across the workspace.
| Area | Permission | Lets a member⦠|
|---|---|---|
| Agents & knowledge | Manage agents | Create, edit, test (playground), publish and delete agents, including their behavior rules, calls to action, A/B tests, appearance and vertical presets. |
| Manage knowledge | Add, edit, re-index and remove knowledge sources, file uploads, curated answers and knowledge-base categories, and close content gaps. | |
| Retry failed pages | Retry indexing a single page from an agent's Knowledge page. | |
| Manage workflows | Create, edit, test and delete workflows. | |
| Conversations | Reply to conversations | Take over live chats, reply to visitors, add internal notes, transfer chats to a teammate and tag conversations. Also needed to watch a conversation live. |
| Manage canned replies | Create, edit, reorder and delete the saved replies operators use in live chats. | |
| Manage tags | Create, rename and delete the tags used to label conversations. | |
| Delete conversations | Permanently delete conversations and tickets, including their messages and captured leads. | |
| Export conversations | Download conversations as a file. | |
| Leads & tickets | Manage leads | Change a lead's status or owner and delete leads from the inbox. |
| Manage tickets | Open tickets, reply to customers, add internal notes, and assign, escalate, merge and update tickets. Members who also hold Manage members and roles are managers: escalated tickets go to them. | |
| Integrations & privacy | Manage integrations | Connect and disconnect Slack, webhooks, Google, Notion and MCP servers. |
| Manage API tokens | Create and revoke API tokens, such as the one the WordPress plugin uses. | |
| Handle privacy requests | Find, export or erase a visitor's data (GDPR / CCPA requests) and read the audit log. | |
| Workspace | Manage members and roles | Invite and remove members, change their roles and create custom roles. |
| Manage workspace settings | Rename the workspace, change live chat settings (business hours, Slack / Teams alerts), lead statuses and lead scoring (Settings βΊ Leads) and ticket auto-escalation, and open system health. | |
| Change widget defaults | Change the workspace's default widget look and copy it onto every agent. | |
| Manage AI keys | Add or remove the workspace's own AI provider keys β only when the platform has enabled bring-your-own-key. | |
| Manage billing | Change the plan, pay by bank transfer, update payment details and download invoices. |
Built-in roles
Four roles ship with every workspace. They are fixed: they can't be edited or deleted, only duplicated into a custom role.
| Role | Permissions |
|---|---|
| Owner | All 19. Every workspace has one owner, and nobody can change or remove them (see The owner). The owner is also the only one who can delete the workspace. |
| Admin | Everything except Manage billing. |
| Editor | Manage agents, Manage knowledge, Retry failed pages, Manage workflows, Reply to conversations, Manage canned replies, Manage tags, Manage leads, Manage tickets, Change widget defaults, Manage AI keys. |
| Viewer | Retry failed pages, Manage tags, Change widget defaults, Manage AI keys β and reading everything. |
The Viewer's four permissions are historical: before roles were configurable, those actions only checked that you were a member of the workspace, so every role could use them. They were kept so no existing member lost access. If you want a strictly read-only role, create a custom role with no permissions.
Custom roles
Open Settings βΊ Roles (/app/settings/roles,
also linked from the Members page as Roles &
permissions). You need Manage members and roles.
- New role β give it a name (unique in the workspace and different from Owner / Admin / Editor / Viewer), an optional description, and tick its permissions. A "Support" role with only Reply to conversations can work live chats and read everything else, and nothing more.
- Duplicate β start from a built-in or custom role and adjust it.
- Edit β renaming or changing permissions takes effect on the members' next request; nobody has to sign in again.
- Delete β when members or pending invitations still use the role, you pick the role they move to; they move and the role is deleted in one step.
In the permission checklist, permissions you don't hold yourself are greyed out: you can't hand them out (see Guards).
Inviting
From /app/members, a member with Manage members and
roles can invite by email with any role they're allowed to hand
out β Admin, Editor, Viewer or a custom role. The invite gets emailed
with a tokenized link to /invitations/{token}; for a
custom role the email and the invite page show the role's name.
Clicking the link:
- Shows the invite preview (workspace name, role).
- Asks the visitor to log in or sign up if they aren't.
- On accept, attaches them to the workspace with the assigned role and redirects to the dashboard.
If the email already belongs to a registered user, they're added straight away with that role and no email is sent.
Invites expire after 7 days. Pending invitations can be revoked from
the Pending invitations section on
/app/members β click Revoke, confirm,
and the row is deleted. The revoke writes an
invitation.revoked entry to the audit log. Already-accepted
invitations cannot be revoked β remove the member from the
Current members list instead.
Changing roles
On /app/members, pick a new role from the member's role
menu. The change takes effect immediately β no re-login needed β and
is written to the audit log as member.role_changed.
Guards
These rules are enforced by the server, whatever the page shows:
- No escalation. You can only create or edit a custom role with permissions you hold yourself, and only invite someone with β or move someone to β a role whose permissions you hold yourself. An Admin can't create a role with Manage billing.
- Nobody above you. You can't change the role of, or remove, a member whose role has permissions you don't hold; nor edit or delete such a custom role.
- Not your own role. Nobody can change their own role.
- Not the owner. The owner can't be removed or given another role, and nobody can be invited as, or moved to, Owner.
- Same workspace only. Custom roles belong to one workspace. Another workspace's role can't be edited, deleted or assigned here.
Removing
Removing a member detaches them from the workspace. Conversations they took over stay attributed to them historically (the audit log keeps actor IDs). Their personal account survives β they just lose access to this workspace. The guards above apply: the owner can't be removed, and nor can a member whose role has permissions you don't hold.
The owner
Every workspace has one Owner β normally the person who created it. The owner holds every permission and is the only one who can delete the workspace. Nobody, including the owner, can remove the owner or give them another role from the Members page, and nobody can be made Owner from there. Transferring ownership is not available in the app.
Multi-workspace users
A user can be a member of any number of workspaces. The sidebar's
workspace switcher (the workspace name card above the user avatar)
lets them jump between memberships and, via the
Create new workspace entry at the bottom of the
dropdown, mint a new one. Each workspace has its own role for the
user β an Owner of one might be a Viewer of another. The number of
workspaces an Owner can mint is capped by
plans.workspaces_limit; the cap is enforced
server-side and the dialog surfaces the error inline.
The "current workspace" is resolved from the user's
default_workspace_id field. Switching writes the new ID.
All tenant-scoped queries thereafter run against that workspace.
When a visitor accepts an invitation while their current default is
a personal/auto-created workspace (one they own themselves), the
accept handler switches their default to the invited workspace so
they land in the right place. If their current default is itself
an invited workspace they're actively using, the accept does NOT
switch β to avoid yanking them out of context.
Audit log
Member and role changes write rows to the audit_logs
table, browsable at /app/audit by members with
Handle privacy requests: member.added,
member.invited, member.role_changed,
member.removed, invitation.revoked,
role.created, role.updated and
role.deleted (which records the replacement role and
how many members and invitations moved).
For developers
- The catalogue is
App\Enums\WorkspacePermission(stored values such asagents.manage,conversations.reply). Built-in sets areWorkspaceRole::permissions(), fixed in code and pinned bytests/Feature/Roles/BuiltInRoleParityTest. - Custom roles live in
workspace_roles(App\Models\CustomRole: a generatedkeysuch ascustom-ab12cd34ef, a name, a description and a JSON list of permissions).workspace_users.roleandinvitations.rolestore a built-in value or such a key. - Membership is "a
workspace_usersrow exists", whatever its role key; a key that matches no role grants no permissions but keeps the member a member. - Check access with
App\Support\Tenancy::can($user, $workspace, WorkspacePermission::β¦)or the policies built on it (for example$user->can('replyToConversations', $agent)or$user->can('manageIntegrations', $workspace)). - The admin UI receives the current member's permissions as the shared Inertia prop
workspacePermissions(read it with theuseWorkspacePermissions()hook) and hides what would 403; the server still enforces every permission.