> ## Documentation Index
> Fetch the complete documentation index at: https://docs.revyops.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Managing Your Workspaces

> Add, import, edit, and archive client workspaces, and manage your agency's team access and login credentials.

## Overview

Your **clients list** (`/dashboard`) is where you manage the roster of client workspaces under your agency, and **Account Settings** (`/dashboard/account-settings`) is where you manage your agency's name and team access. Together these are the tools an agency admin uses to stand up and maintain their workspace structure.

Everything on this page is restricted to the `admin` role. **Add client**, **Import clients**, **Edit client**, and **Account Settings** are gated by route middleware — a client-role user who navigates to any of those URLs directly is redirected straight to the login page, no "access denied" screen. The clients list itself (`/dashboard`) isn't middleware-gated the same way: it's hidden behind a template check for the admin role, and a client-role user landing there is instead redirected to their own client workspace at `/dashboard/client`.

<Note>
  If your agency hasn't been activated yet, the clients list is replaced with an onboarding screen asking you to book a call. Nothing described below is available until an account manager whitelists your agency.
</Note>

***

## Adding a client workspace

Go to **Clients → Add client** (`/dashboard/add-client`). The form asks for one thing: the client's name.

<Steps>
  <Step title="Enter a name">
    Type the client name and click **Add client**.
  </Step>

  <Step title="Uniqueness check">
    RevyOps checks that no other *active* client in your agency already has that name. Archived clients are excluded from this check, so you can reuse the name of a client you archived earlier.
  </Step>

  <Step title="Plan limit check">
    If your agency has a `maxClients` limit and you're already at it, the form blocks the save and shows: *"You have reached the maximum number of clients (N) for this account. Please contact us to increase this limit."*
  </Step>

  <Step title="Redirect">
    On success you're returned to the clients list. The new workspace gets a default set of Smart Views seeded in the background.
  </Step>
</Steps>

Adding a client only creates the workspace shell (name + ownership). Integrations, custom fields, and everything else are configured separately, per client, after it exists.

***

## Bulk-importing clients via CSV

Go to **Clients → Import clients (CSV)** (`/dashboard/import-clients`). This is the faster path when you're onboarding several clients at once.

### File requirements

* Max file size: **2 MB**
* The only required column is `Client name` — rows without it are dropped silently before the preview even shows them.
* Three optional columns tag each new client with integration flags: `Integrate with Clay`, `Integrate with Hubspot`, `Integrate with Instantly`.

<Warning>
  The on-screen upload instructions describe these as *"Integrate with Clay (yes/no)"* etc., but that `(yes/no)` describes the expected **cell value**, not the column header — the parser looks for a header literally named `Integrate with Clay`. If you name the column `Integrate with Clay (yes/no)` to match the instructions text, the parser won't find it and silently treats every row as not integrated with Clay.
</Warning>

Accepted "yes" values (case-insensitive) are `yes`, `y`, `true`, `1`, and `on`; anything else (including a missing column) is treated as "no."

<Warning>
  The three integration columns only tag the new client record with an `integrations` list — they don't actually connect Clay, HubSpot, or Instantly. You still have to configure and authenticate each integration from the client's own Integrations page after import.
</Warning>

### What happens after upload

1. RevyOps parses the CSV and shows a preview table with every row and a Ready/Duplicate status chip.
2. **In-file duplicates** — if the same client name appears more than once in your CSV, only the first occurrence is kept; the rest are dropped and listed in a warning banner.
3. **Existing-name duplicates** — names that already exist as active clients in your agency are flagged in a separate warning and will be skipped on import (they still show in the preview table, marked "Duplicate").
4. **Plan limit** — if importing every non-duplicate row would put you over your `maxClients` limit, the whole import is blocked until you trim the file.
5. Click **Import N clients** to commit. Rows flagged as duplicates are excluded from the count and from the write.

There's no per-row retry or partial-failure UI — the import fires one write per client and reports a single success message with the count that went through.

***

## Editing a client's name

From the clients list, click the pencil icon on a row, or go directly to `/dashboard/edit-client/[id]`. The edit form is the same component as Add, just pre-filled with the current name.

The name-uniqueness check runs again on save (skipped entirely if you didn't actually change the name).

The edit form only works for clients currently in your active clients list. If you reach the URL for a client that's archived or belongs to a different agency, the form can't find it locally and fails to load with a generic error rather than showing you the name field — there's no dedicated "this client is archived" message, just a load failure.

Editing the name here only changes the display name — it doesn't touch any connected integration's own naming or IDs.

***

## Archiving a client

There's no separate archive page — click the trash icon on a client's row in the clients list, which opens a confirmation dialog: *"Are you sure you want to archive **\[name]**? Archived clients will be removed from the clients list."*

Confirming calls a backend endpoint (`POST /api/ui/{client_id}/archive`) rather than writing to the client record directly from the browser. That endpoint, in addition to marking the client archived:

* Prefixes (effectively disables) that client's own RevyOps API keys — the credentials used to push data **into** RevyOps via API or webhook — and clears them from the lookup cache. This doesn't touch credentials for outbound integrations like Instantly or HubSpot.
* Disables that client's HeyReach webhooks

If the archived client was your currently-selected workspace, your workspace selection is cleared. The client immediately drops out of the active clients list.

<Warning>
  There's no unarchive button anywhere in the UI. The backend endpoint technically supports un-archiving (the same route accepts `archived: false` and reverses the API-key and webhook changes), but no screen calls it that way — reactivating an archived client today means asking RevyOps to do it for you.
</Warning>

Archiving doesn't delete the client's data (contacts, companies, campaign history) — it only removes the workspace from your active list and severs its live integration connections.

***

## Plan limits

Your agency's `maxClients` permission (set by RevyOps, not self-service) caps how many active clients you can have at once. It's enforced in three places:

| Where                   | Behavior when at the limit                                                                                                        |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **Add client**          | Save is blocked with an inline error explaining the limit                                                                         |
| **Import clients**      | The whole CSV import is blocked if it would push you over                                                                         |
| **Clients list header** | Both the **Add client** and **Import clients (CSV)** buttons are disabled; hovering **Add client** shows a tooltip with the limit |

Archived clients don't count against the limit — archiving one frees up a slot. If you need more room, the tooltip and error messages both point you to contact RevyOps.

***

## Account settings

Go to **Settings → Account Settings** (`/dashboard/account-settings`) to manage your agency's name and team roster.

### Renaming your agency

Click the pencil icon next to your account name, edit the name in the dialog, and save. This updates the `name` field on your agency's record — it's the display name used in team-facing UI, not a slug or domain.

### Inviting team members

Click **Invite users** to open the invite dialog:

1. Paste one or more email addresses into the text box — separated by commas, spaces, or newlines. RevyOps parses them live, validates the format, and de-duplicates as you go, showing each valid address as a removable chip.
2. Pick a role for the whole batch:
   * **Admin** — full access to everything on this page, plus every client workspace.
   * **Client** — scoped to one workspace, chosen from a dropdown of your active clients. You can't send a Client-role invite without picking a client.
3. Click **Send Invitations**.

Every email in the batch gets the same role. To invite people into different roles or different clients, send separate batches.

### What happens when you send an invite

This works differently depending on the invited role and one agency-level setting (`autoGenerateClientCredentials`, on by default):

<Tabs>
  <Tab title="Admin invite">
    An invitation record is created and an email is sent with a signup link (`/invitation/{id}`). The invitee sets their own password when they accept. The email text says the link "expires in 7 days," but no expiry date is actually written onto the invitation record — in practice the link stays valid until it's accepted or you remove the pending invitation yourself.
  </Tab>

  <Tab title="Client invite, auto-generate ON (default)">
    No email-link flow, and **no email is sent to the invitee at all.** RevyOps creates the Firebase login immediately, generates a random 16-character password, and marks the invitation "accepted" right away. The only place that password appears is a **Client Login Credentials** dialog shown once to you, the inviting admin, with copy-to-clipboard fields for the email and password — you're responsible for getting those credentials to the client yourself (Slack, a call, whatever channel you'd use). The dialog doesn't reopen after you close it; use the Users table (below) if you need to see the password later.
  </Tab>

  <Tab title="Client invite, auto-generate OFF">
    Falls back to the same signup-link email flow as an Admin invite, with the client scoping already attached to the invitation.
  </Tab>
</Tabs>

If the email already has an account, the invite fails with *"A user with this email already exists"* and the invitation record is rolled back — nothing is left pending.

### The team roster

The Users table lists every active member and pending invitation for your agency: email, role (and, for Client-role rows, which client they're scoped to), a password column, and an actions menu.

* **Pending** invitations show a "Pending" chip and no password controls.
* **Active** members created through the auto-generated-credentials flow show a masked password with a **View** button; viewing it reveals it in place, with copy and hide controls next to it.
* **Active** members who set their own password (accepted-link flow) show "Managed by user" instead — RevyOps never stores their password.
* Your own row is marked **You** and has no actions menu.

### Resetting a password

From a member's actions menu, **Reset password** (only shown for members whose password RevyOps already has on file) asks for confirmation, then calls a backend endpoint that generates a new random password and updates it in Firebase Auth. The new password is shown to you immediately, the same way a freshly-created one would be.

### Removing a team member

Only the agency's original owner (the user who created the agency) sees **Remove from account** in the actions menu. What it does depends on status:

* **Pending invitation** — the invitation record is deleted outright. The invite link stops working.
* **Active user** — their `agencyId` is cleared. They keep their login but lose access to your agency's workspaces; nothing about their historical data or activity is deleted.

There's no bulk-remove — it's one member at a time, with a confirmation click through the actions menu each time.
