Roles & access
The platform has four roles, each with a different default view of the dashboard. Specific permissions on top of the role can be granted per-user.
| Role | Who | Sees |
|---|---|---|
| SUPER_ADMIN | Platform operator (you) | Every agency, every workspace. Used for support + impersonation. |
| AGENCY_ADMIN | Agency owner | Their entire workspace — every client, every channel, billing, team. |
| AGENCY_USER | Agency agent | Whatever subset of the workspace they’re assigned to. |
| CLIENT_USER | The agency’s customer | Only their own client row — their own channels, contacts, flows, bookings. |
Permission overrides
Every role has a default set of chat.* / gmb.* / team.* / etc. permissions.
AGENCY_ADMIN can edit individual user grants on top — e.g. give one CLIENT_USER the
extra chat.view_reports permission without giving it to all CLIENT_USERs.
See Team & permissions for the full grant matrix + how to delegate.
Tenant scoping
Every API call is scoped by:
- agency_id — the agency the user belongs to
- client_id — null for AGENCY_* roles; populated for CLIENT_USER
A CLIENT_USER literally can’t read another client’s contacts because the SQL
WHERE client_id = $1 filter is applied at the service layer. The filter is
fail-closed: if a CLIENT_USER somehow has clientId === null in their JWT, queries
are scoped to a sentinel id that matches no rows.
Impersonation
SUPER_ADMIN can impersonate any user from /dashboard/team → user row → “Impersonate”.
The dashboard chrome shows a yellow banner (“You are viewing as: …”) and every
subsequent action is recorded with both the actor + the impersonated user in the audit
log.