# Manage API keys

API keys provide programmatic access to your Viam resources. Each API key is scoped to a specific level of the [resource hierarchy](https://docs.viam.com/organization/overview/) and assigned a role, so you can control exactly what it can access.

Use API keys to authenticate SDK connections, CLI scripts, and automated workflows.

## Choose the right scope

Every API key is scoped to an organization, location, or machine. Follow the principle of least privilege: grant the narrowest scope that lets the key do its job.

| Use case                                      | Recommended scope | 
|-----------------------------------------------|-------------------| 
| SDK connection to one machine                 | Machine           | 
| Automated deployment script for one site     | Location          | 
| CI/CD pipeline for module uploads             | Organization      | 
| Monitoring dashboard for a location          | Location          |

## Choose the role

Each key is assigned a role: **Owner** or **Operator**. Owner has full access at the key’s scope. Operator can control machines through the **CONTROL** tab and view some data, but cannot configure machines, view logs, or manage members.

How you create the key determines which roles you can choose:

| Creation path | Roles supported              | 
|---------------|-------------------------------| 
| Viam app      | Owner or Operator             | 
| Python SDK    | Owner or Operator             | 
| Go SDK        | Owner or Operator             | 
| CLI           | Owner only (hardcoded)       |

If you need an Operator-role key, create it from the Viam app or an SDK. The CLI’s `viam organizations api-key create`, `viam locations api-key create`, and `viam machines api-key create` commands always produce Owner-role keys.

For an SDK example with Operator role, see [Create an Operator-role key with the SDK](https://docs.viam.com/organization/api-keys/#create-an-operator-role-key-with-the-sdk) below.

For the full permission matrix, see [Permissions](https://docs.viam.com/organization/rbac/).

## Create an API key

- [Web UI](https://docs.viam.com/organization/api-keys/#tabset-organizationapi-keys-1-0)
- [CLI](https://docs.viam.com/organization/api-keys/#tabset-organizationapi-keys-1-1)
- [Python](https://docs.viam.com/organization/api-keys/#tabset-organizationapi-keys-1-2)

1. Navigate to the level where you want to create the key:
   - **Organization**: Click the organization name in the top navigation bar, then **Settings**. Find the **API keys** section.
   - **Machine**: Navigate to the machine’s page and click the **CONNECT** tab.
2. Click **Generate key** or **Add key**.
3. Give the key a descriptive name (for example, `production-deploy-script` or `warehouse-monitoring`).
4. Copy the key and key ID immediately. You will not be able to see the key again.

Create a key at the organization, location, or machine level:

```sh
viam organizations api-key create --org-id <org-id> --name "deploy-pipeline"
Successfully created key:
Key ID: xxxx-xxxx
Key Value: xxxx-xxxx-xxxx
Keep this key somewhere safe; it has full write access to your organization
```

```sh
viam locations api-key create --location-id <location-id> --name "warehouse-monitoring"
Successfully created key:
Key ID: xxxx-xxxx
Key Value: xxxx-xxxx-xxxx
Keep this key somewhere safe; it has full write access to your location
```

```sh
viam machines api-key create --machine-id <machine-id> --name "arm-control"
Successfully created key:
Key ID: xxxx-xxxx
Key Value: xxxx-xxxx-xxxx
Keep this key somewhere safe; it has full write access to your machine
```

```python
from viam.app.app_client import APIKeyAuthorization
from viam.app.viam_client import ViamClient

client = await ViamClient.create_from_dial_options(...)
api_key, api_key_id = await client.app_client.create_key(
    org_id="<org-id>",
    authorizations=[\
        APIKeyAuthorization(\
            role="owner",\
            resource_type="location",\
            resource_id="<location-id>"\
        )\
    ],
    name="warehouse-monitoring"
)
```

#### Important

Store your API key securely. Viam does not store the key value after creation. If you lose it, you must rotate or create a new key.

### Create an Operator-role key with the SDK

The CLI does not expose a `--role` flag, so use the Viam app or an SDK to create an Operator-role key. The Python example below passes `role="operator"` to `APIKeyAuthorization`:

```python
api_key, api_key_id = await client.app_client.create_key(
    org_id="<org-id>",
    authorizations=[\
        APIKeyAuthorization(\
            role="operator",\
            resource_type="location",\
            resource_id="<location-id>",\
        )\
    ],
    name="control-dashboard-readonly",
)
```

## List API keys

- [Python](https://docs.viam.com/organization/api-keys/#tabset-organizationapi-keys-2-0)
- [Go](https://docs.viam.com/organization/api-keys/#tabset-organizationapi-keys-2-1)

```python
keys = await client.app_client.list_keys(org_id="<org-id>")
for key in keys:
    print(f"{key.api_key.id}: {key.api_key.name}")
```

```go
keys, err := client.ListKeys(ctx, "<org-id>")
for _, key := range keys {
    fmt.Printf("%s: %s\n", key.APIKey.ID, key.APIKey.Name)
}
```

## Rotate a key

Key rotation lets you generate a new key value while keeping the same authorizations. This is useful for periodic credential rotation or when a key may have been exposed.

To rotate without downtime:

1. Create a new key with the same scope and role.
2. Update all consumers (scripts, SDK connections) to use the new key.
3. Verify the new key works.
4. Delete the old key.

You can also rotate in place with the SDK, which generates a new key value and invalidates the old one immediately:

```python
new_key, new_key_id = await client.app_client.rotate_key(id="<api-key-id>")
```

```go
newKeyID, newKey, err := client.RotateKey(ctx, "<api-key-id>")
```

#### Caution

`rotate_key` invalidates the old key immediately. Any consumer still using the old key will lose access. For zero-downtime rotation, use the create-then-delete approach instead.

## Rename a key

Give a key a more descriptive name:

```go
_, _, err := client.RenameKey(ctx, "<api-key-id>", "new-descriptive-name")
```

#### Note

`RenameKey` is currently available in the Go SDK only.

## Delete a key

- [Python](https://docs.viam.com/organization/api-keys/#tabset-organizationapi-keys-4-0)
- [Go](https://docs.viam.com/organization/api-keys/#tabset-organizationapi-keys-4-1)

```python
await client.app_client.delete_key(id="<api-key-id>")
```

```go
err := client.DeleteKey(ctx, "<api-key-id>")
```

## Use an API key

### SDK connection

Use an API key to connect to a machine from your code:

```python
from viam.robot.client import RobotClient

opts = RobotClient.Options.with_api_key(
    api_key="<your-api-key>",
    api_key_id="<your-api-key-id>"
)
robot = await RobotClient.at_address("<machine-address>", opts)
```

### CLI authentication

Authenticate the CLI with an API key:

```sh
viam login api-key --key-id <key-id> --key <key>
```

To manage multiple API keys, use CLI profiles:

```sh
viam profiles add --profile-name production --key-id <key-id> --key <key>
```

## Best practices

- **Name keys descriptively.** Include the purpose and scope: `production-deploy-ci`, `warehouse-3-monitoring`, `dev-testing`.
- **Use the narrowest scope possible.** A script that only reads sensor data from one machine should use a machine-scoped Operator key, not an org-scoped Owner key.
- **Rotate keys periodically.** Use the create-then-delete pattern to avoid downtime.
- **Revoke keys when people leave.** List all keys with `list_keys` and delete any associated with departed team members.
- **Do not commit keys to version control.** Use environment variables or secret management tools.
