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 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 caseRecommended scope
SDK connection to one machineMachine
Automated deployment script for one siteLocation
CI/CD pipeline for module uploadsOrganization
Monitoring dashboard for a locationLocation

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 pathRoles supported
Viam appOwner or Operator
Python SDKOwner or Operator
Go SDKOwner or Operator
CLIOwner 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 below.

For the full permission matrix, see Permissions.

Create an API key

  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:

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
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
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
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"
)

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:

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",
)

The Go SDK accepts the same role values through APIKeyAuthorization and CreateKey.

List API keys

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}")
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:

new_key, new_key_id = await client.app_client.rotate_key(id="<api-key-id>")
newKeyID, newKey, err := client.RotateKey(ctx, "<api-key-id>")

Rename a key

Give a key a more descriptive name:

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

Delete a key

await client.app_client.delete_key(id="<api-key-id>")
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:

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)

Script on your laptop

A script that runs on your own computer and connects to a machine needs three things: the machine address, an API key, and the API key ID. Find the address, key, and key ID on the machine’s CONNECT tab in the Viam app, or create a key as described in Create an API key.

Keep the key and key ID out of your source code by reading them from environment variables. Set them in the shell that launches your script:

export VIAM_API_KEY_ID="<your-api-key-id>"
export VIAM_API_KEY="<your-api-key>"

Then read them in your script and pass them to the SDK along with the machine address:

import os

from viam.robot.client import RobotClient

opts = RobotClient.Options.with_api_key(
    api_key=os.environ["VIAM_API_KEY"],
    api_key_id=os.environ["VIAM_API_KEY_ID"],
)
robot = await RobotClient.at_address("<machine-address>", opts)

The Python SDK reads VIAM_API_KEY and VIAM_API_KEY_ID on its own only in ViamClient.create_from_env_vars(), which connects to the Viam app rather than to a single machine. For RobotClient, your script reads the variables itself, as above.

Use a viam.json file instead

Each machine part has a viam.json file that holds the part’s cloud credentials under the cloud key: the part ID, a part secret, and an api_key block with a key ID and key. To get the file on another computer, copy the machine’s Machine cloud credentials from the machine’s status menu in the Viam app and save them as viam.json. A script can read the api_key block and authenticate with it the same way as in the previous section:

import json
from pathlib import Path

from viam.robot.client import RobotClient

cloud = json.loads(Path("viam.json").read_text())["cloud"]
opts = RobotClient.Options.with_api_key(
    api_key=cloud["api_key"]["key"],
    api_key_id=cloud["api_key"]["id"],
)
robot = await RobotClient.at_address("<machine-address>", opts)

On a computer where viam-agent is installed, this file is at /etc/viam.json. Some viam.json files have only the part ID and secret, with no api_key block. The Python SDK can also authenticate with that secret as credentials of type robot-secret, when your script connects through the machine’s cloud address. For a script on a laptop, prefer a separate API key scoped to the machine, because you can revoke it without touching the machine.

CLI authentication

Authenticate the CLI with an API key:

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

To manage multiple API keys, use CLI profiles:

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

See CLI authentication for more details.

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.