---
title: Manage members and API keys
description: "Add people to an organization and a project, give them the right role, and mint a scoped API key for an integration."
---

Two kinds of access exist side by side: **people**, who sign in and hold roles, and **keys**, which authenticate an integration as the person who created them. This guide covers both, and the one rule that connects them.

## Add someone to the organization

Open **Settings**, then **Organization**. The members list is there, along with your own role and the organization's identity-provider settings.

**Add member** invites someone by email address. They receive a single-use invitation link, and following it activates their account. If the invitation is lost or expires, re-inviting the same person issues a fresh one and invalidates the old.

An organization member holds one of three roles: `owner`, `admin` or `member`. Ownership transfers explicitly (**Make owner** in a member's row menu), and an organization always has one. Owners and admins create projects and may remove any of the organization's cloud credentials. Every member reads the device fleet by virtue of membership. A `member` is not read-only: in the projects they belong to, members register models, start and cancel their own benchmarks and deploy. Read-only access is a project role, `viewer`. [Roles](../concepts/roles.md) is the full table.

Removing a member ends their sessions, API keys, and project and team memberships in that organization at once; demoting one narrows their project access the same way. An API key stops working while its owner's account is suspended or deleted, and is deleted with the account.

## Add someone to a project

Organization membership does not grant access to a project's work. Open the project's dashboard and use the **Members** tab, then **Manage Members**.

A project member holds one of four roles.

| Role | Give it to |
| --- | --- |
| `owner` | Whoever is accountable for the project. The last owner cannot be removed or demoted. |
| `admin` | Someone who manages the project's members and resources. |
| `developer` | Someone who registers models and runs benchmarks. |
| `viewer` | Someone who reads results. |

The distinction that catches people out: [devices are organization-scoped](../concepts/organization-and-project.mdx#devices-are-the-exception), so every project sees the same fleet. Everything else (models, runs, services, artifacts, licenses) belongs to one project and is invisible from the others.

Project roles say nothing about devices. A project admin cannot mint an enrollment token or change a device unless the organization grants that capability separately. Creating a project is likewise an organization owner's or admin's action, not something a project role confers.

## Mint an API key

Open **Settings**, then **Developer access**. **Create key** takes a name (`CI pipeline`, `nightly sweep`) and the scope the key should carry.

The key is shown once, at creation. Copy it then; the platform stores only its hash and a short display prefix, so a lost key is replaced rather than recovered.

A key also acts in the **project** that is open in the project switcher when you create it: benchmarks and deployments made through the key land there, and a deployment of another project answers `404` to it by id. Create the key with the right project open, and name it after the project.

Use it as a bearer token:

```bash
curl -H "Authorization: Bearer clika_your_api_key" \
  https://platform.clika.io/api/devices
```

Or save it to a CLI profile, which prompts without echoing so nothing lands in your shell history:

```bash
clika-cli --base-url https://platform.clika.io login --api-key
```

### Scopes, and why a key can never exceed you

A key authenticates as the user who created it, and its scope is an allowlist of capabilities. The permissions a request actually gets are **the owner's capabilities intersected with the key's scope**, recomputed on every request. Two consequences follow.

- A key can never do something its owner cannot, and demoting the owner narrows every key they own immediately, with no revocation sweep to run.
- A key can do considerably less than its owner, which is the point. A key scoped to reading devices and running benchmarks is a safe thing to put in CI, or to hand to an [MCP client](../mcp/index.md), because no prompt and no script can make it edit members or licenses. Membership itself is out of every key's reach, whatever the scope: see [What a key can never do](#what-a-key-can-never-do).

An empty scope grants nothing, which is a useful thing to create deliberately. It is not the same as the unrestricted scope some older keys carry.

### The three templates

The creation dialog offers three ready-made scopes, expanded server-side from what you yourself hold.

| Template | What it grants |
| --- | --- |
| **viewer** | Every read and list capability you hold. A safe default for dashboards, reporting and anything that only observes. |
| **worker** | The viewer set plus write, cancel and invoke. This is the CI shape: it can register a model, launch a benchmark, cancel one, and call a model deployment. |
| **admin** | Every capability you hold that a key may carry at all, including delete. |

No template ever includes the sharper verbs: `delete` outside the admin template, and never `exec`, `tunnel`, `remote_desktop`, the cross-team `read_all` and `manage_all`, the storage `test` probes, or `manage`. If a key needs one of those, grant it explicitly and know why. `runtime_sdk:download` sits in the Admin template only (the dialog marks it "In Admin"), although every organization role holds it: tick it under **Advanced** when the key will run `clika-cli runtime-sdk`. A key created by a member is capped to what that member holds: the dialog greys out the boxes for capabilities the member lacks, and its counter shows how many permissions the key will carry.

### The capabilities a key can carry

Capabilities are named `resource:action`. What the scope catalogue offers you is bounded by what you hold, so your own list may be shorter than this one.

| Resource | Capabilities | Holding them admits |
| --- | --- | --- |
| `devices` | `read`, `write`, `delete`, `exec`, `tunnel`, `remote_desktop`, `read_all`, `manage_all` | Reading and managing the fleet. `exec` runs arbitrary commands on a device, `tunnel` opens a TCP tunnel to one, `remote_desktop` opens an interactive screen and keyboard session, and the two `_all` forms are the cross-team administrative view. |
| `jobs` | `read`, `write`, `cancel` | Reading, submitting and cancelling jobs, which is what launching a benchmark needs. |
| `artifacts` | `read`, `write`, `delete` | Reading the library, uploading and updating artifacts, and deleting them. |
| `model_serving` | `read`, `write`, `invoke` | Seeing model deployments, managing them, and calling one through the platform proxy. `invoke` is separate on purpose: seeing a deployment is not the same as spending its GPU. |
| `services` | `read`, `write` | Managing the device-side services subsystem. |
| `metrics` | `read`, `write` | Reading and writing metric definitions and data points. |
| `alerts` | `read`, `write` | Reading and managing alert rules. |
| `events` | `read` | Reading the organization's event stream: device, job, command, transfer and alert activity. |
| `projects` | `create`, `read`, `write`, `delete` | Creating projects, which the organization's owners and admins hold, and managing projects and their membership. |
| `orgs` | `read`, `write` | Reading and updating the organization record (its name and settings). `write` also invites and removes members, transfers ownership and deletes the organization, so give it to a key only when that key must manage the organization. |
| `teams` | `read`, `write` | Creating and renaming teams. Team membership and deleting a team take a signed-in session. |
| `webhooks` | `read`, `write` | Managing webhooks. |
| `hosted_devices` | `read`, `write`, `delete` | Renting and running on hosted phones. `write` is the capability that spends money, since hosted devices bill by the minute. |
| `cloud_credentials`, `cloud_instances` | `read`, `write`, `delete` | Managing stored cloud provider credentials and the instances created with them. |
| `credentials` | `read`, `write`, `delete` | Managing container-registry credentials, which external artifacts use to pull. |
| `file_storage` | `read`, `write`, `test` | Viewing and changing the artifact storage backend. `test` makes live outbound probes against the configured bucket. |
| `license` | `read` | Reading the organization's plan and activation codes. |
| `license_profiles` | `read`, `write` | Reading and curating entitlement profile templates. |
| `project_licenses` | `read` | Reading a project's runtime credentials. |
| `runtime_deployments` | `read` | Reading the runtime deployment plane. |
| `runtime_sdk` | `download` | Listing the ClikaRT release archives the deployment offers and minting a download link for one. Every built-in organization role holds it. See [Download the ClikaRT SDK](download-the-clikart-sdk.md). |
| `vpn` | `read`, `write`, `delete` | Managing VPN configuration. |

### What a key can never do

Some capabilities are refused to every key, however you scope it, because a credential that holds them can widen itself and the scope would be decorative. They stay available to a signed-in session with the right role.

- **Identity and access**: creating or editing users, roles, and SSO configuration.
- **Platform administration**: the `/api/admin` surface, platform settings, and support access.
- **Minting credentials**: issuing a runtime credential or writing the organization's license. Both create new authority, which is exactly what a leaked key must not be able to do.
- **Billing**: re-planning the organization or starting a payment flow.

A second group is refused to every key by route rather than by capability. These are the organization's identity writes: inviting or re-inviting a member, changing a member's role, removing a member, issuing a member's password reset link, transferring ownership, deleting the organization, adding or removing a team member, deleting a team, and approving or denying a support-access request. A key carrying `orgs:write` or `teams:write` still cannot call them; neither can a key created before scopes existed. They answer `API_KEY_ROUTE_SESSION_ONLY`, and an MCP client authenticated with a key is not offered them as tools. Sign in to do these.

## Troubleshooting

**The browser works, my API key gets 403 on one route.** Read the error code. `API_KEY_SCOPE_INSUFFICIENT` names the capability the route needs and your key does not carry, which you fix by re-scoping the key. `API_KEY_ROUTE_SESSION_ONLY` means the route is one of the identity writes listed above: no key reaches it whatever its scope, so sign in and do it from the web application; the CLI signs in with an API key only. `API_KEY_ROUTE_NOT_SCOPEABLE` means the route declares no capability at all, so no key can reach it while a signed-in session still can; that is a gap in the deployment's route declarations rather than something you can fix from the key, so report the route to whoever runs the deployment.

**A member cannot see a project's resources.** Check project membership rather than organization membership. A resource in a project you are not a member of answers `404`, deliberately, so that probing ids reveals nothing.

**An invitation link does not work.** Links are single-use and expire. Re-inviting issues a new one and invalidates the previous.

## Related pages

- [Organization and project](../concepts/organization-and-project.mdx): what each container holds.
- [Using with AI (MCP)](../mcp/index.md): the main consumer of a scoped key.
