# Roles & permissions

**A Workspace has four roles: `owner`, `admin`, `member` and `client`.** The first three are your agency; `client` is an external customer you invited to specific projects. This page says what each one may actually do, area by area, because "admin-only" is true of fewer things than people assume.

## Prerequisites

- A Workspace and the `owner` or `admin` role, to change anyone's role
- For the API examples: an API key and your Workspace ID from [Developer tools → API keys](https://app.hlix.ai/developer-tools/api-keys)

## The four roles

| Role | Who it is | The one-line summary |
| --- | --- | --- |
| `owner` | Whoever created the Workspace | Everything, including deleting the Workspace |
| `admin` | Agency leads | Everything except deleting the Workspace |
| `member` | Agency engineers and delivery staff | Full access to project work, secrets and environments; cannot change money or membership, cannot delete a project, cannot change Workspace-wide provider settings |
| `client` | Your customer, invited to named projects | Sees only the projects shared with them, and only the delivery surface of those |

Creating a Workspace makes you its `owner`. Every account gets one Workspace of its own on first sign-in.

**`member` is an agency role, not a limited one:** A `member` can read and write project secrets, edit environments, change per-role model preferences, and create projects. If you need someone with narrow access, invite them as a **client collaborator** on specific projects. `member` is the wrong tool for a restricted teammate.

## Membership

| Action | `owner` | `admin` | `member` | `client` |
| --- | --- | --- | --- | --- |
| Invite a member | yes | yes | no | no |
| Change a member's role | yes | yes | no | no |
| Remove a member | yes | yes | no | no |
| Update Workspace details | yes | yes | no | no |
| **Delete the Workspace** | **yes** | no | no | no |

`client` is not an invitable Workspace role. A client joins by accepting a **project** invitation, which creates their membership and their project grant together — see [Project collaborators](#project-collaborators) below. A project invitation is valid for seven days.

## Billing

Billing here is your agency's own hlix subscription, not the invoices you issue to your customers.

| Action | `owner` | `admin` | `member` | `client` |
| --- | --- | --- | --- | --- |
| Read the subscription and current spend | yes | yes | yes | **no** |
| Start a checkout | yes | yes | no | no |
| Open the billing portal | yes | yes | no | no |
| Set or clear the spend cap | yes | yes | no | no |

A client collaborator asking for billing gets a flat refusal:

```json
{"error": "Billing is agency-only"}
```

A `member` can read it but not change it:

```json
{"error": "Admin or owner role required"}
```

## Settings, secrets and configuration

Settings split across two tiers, and the line between them is not always where you would expect.

**Owner or admin only:**

- Workspace-wide harness and coder selection
- Bring-your-own model provider keys — *writes* only; `member` can read which providers are configured
- Web search provider configuration
- Chat channel integrations (installing and revoking)
- Workspace-wide defaults: notification preferences, privacy settings, project defaults
- The spend cap
- Archiving, unarchiving and **deleting** a project

**Any agency role, including `member`:**

- Project secrets — create, update, delete, list
- Project environment configuration
- Per-role model preferences
- Reading Workspace-wide defaults, and every personal preference
- Creating a project, and running work on it

**No client collaborator, ever:** none of the above. Secrets, environments, integrations, model configuration, logs, events and the approval queue are invisible to the `client` role, not merely refused.

Per-**project** harness and coder selection is a project-administration action, which means it is agency-only even for a client collaborator with steering rights:

```json
{"error": "Project administration is restricted to the agency"}
```

## Approvals

Resolving a [pending request](/running/approvals/) — answering an agent's question, or accepting or declining a proposed cycle — is agency work.

A client collaborator cannot resolve a pending request, and there is no exception. The approval queue is invisible to the `client` role, so a client's request finds nothing to act on. This matches [Tenancy & isolation](/security/tenancy/#the-second-fence-client-collaborators).

What a client *can* answer is a separate record with a different audience: a **deliverable approval**, which asks a named customer reviewer to sign off on one published revision. It is kept apart from the agency's own queue, so a customer's sign-off and an internal decision are never mixed. See [Deliverables & approvals](/clients/deliverables/).

## Project collaborators

A client collaborator is invited to **one project at a time**, and their grant carries a single switch.

| Grant | What it allows |
| --- | --- |
| Default (read) | See the project, its cycles, tasks and messages. Comment. |
| `canSteer` | Additionally dispatch and drive an agent run on that project. |
| — | Project administration is refused for every client, with or without `canSteer`. |

Only an `owner` or `admin` can invite a collaborator, list invitations, revoke one, toggle `canSteer`, or remove a collaborator. A `member` cannot.

Without `canSteer` a client who tries to start a run gets:

```json
{"error": "Read-only access to this project"}
```

## The audit log

Reading the [audit log](/security/audit-log/) requires `owner` or `admin`. There is no narrower, project-scoped audit view for a `member` or a `client` — every audit route answers the same way:

```json
{"error": "admin only"}
```

## API keys

Create keys in [Developer tools → API keys](https://app.hlix.ai/developer-tools/api-keys). They are prefixed `hlix_` and shown once.

**A key authenticates; it does not authorize.** It identifies the person who created it, and hlix re-reads that person's role from the live membership record on every request. So:

- A key cannot reach a Workspace its owner is not a member of.
- A key does not freeze the role it was created under. Demote the owner and the key's reach shrinks with them; remove them and it stops working.
- A key carries no separate scopes. It can do exactly what its owner can do, no more and no less.

Keys are rate limited to 100 requests per minute. They do **not** expire by default — set an expiry explicitly when you create one if you want the key to lapse.

Every `/v1/api/*` route accepts either an API key in the `x-api-key` header or the browser session cookie. The sign-in endpoints themselves are session-only.

## Check a role from the API

```bash
curl -sS "$HLIX_BASE_URL/v1/api/audit-log?limit=1" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID"
```

Expected result for an `owner` or `admin`: `{"items": [...], "nextCursor": …}`. For anyone else, a `403` carrying `{"error": "admin only"}` — which is a quick, non-destructive way to confirm which tier a key is operating at.

## If a permission check surprises you

- **`{"error": "admin only"}` with `403`.** The route needs `owner` or `admin` and your key's owner is a `member`. This is the message the audit log, Workspace defaults, provider writes, channel integrations, and archiving or deleting a project all use.
- **`{"error": "Admin or owner role required"}` with `403`.** Same tier, different wording — billing checkout, the billing portal, and the spend cap use this one.
- **`{"error": "Billing is agency-only"}` with `403`.** You are acting as a client collaborator. Billing has no client-facing view; customer invoices are a different surface.
- **`{"error": "Project administration is restricted to the agency"}` with `403`.** A client collaborator attempted a configuration change. Granting `canSteer` does not lift this — nothing does.
- **`{"error": "Read-only access to this project"}` with `403`.** A client collaborator without `canSteer` tried to dispatch work. An agency admin can grant it per project.
- **`{"error": "Project not found"}` with `404` for a project you know exists.** A client collaborator with no grant on it. The `404` is deliberate and does not confirm existence — see [Tenancy & isolation](/security/tenancy/#why-a-strangers-project-answers-404).
- **A `member` can read your project secrets and you did not expect that.** That is the design: `member` is an agency role. Use a client collaborator grant for anyone who should not see credentials.
- **An API key stopped working after a role change.** Expected. The role is resolved live on every request, not captured when the key was minted.

## Where to go next

| If you want to… | Read |
| --- | --- |
| Understand the boundary these roles sit inside | [Tenancy & isolation](/security/tenancy/) |
| See what gets recorded when someone uses a permission | [Audit log](/security/audit-log/) |
| Resolve a pending request | [Approvals](/running/approvals/) |
| Create a key and sign in | [Authenticate](/getting-started/authentication/) |

## Next steps

[Tenancy & isolation](/security/tenancy/)
  [Audit log](/security/audit-log/)
  [Approvals](/running/approvals/)
  [Authenticate](/getting-started/authentication/)