Skip to content

Admin

API Keys

Minting, rotating, and revoking app keys and per-agent keys.

Alter recognizes four key shapes. Root and agent keys can be created in the developer portal; derived keys are programmatic only.

PrefixUsed byWhere it’s minted
alter_rk_… (runtime)Backend services using the App SDK classApp → API Keys, key type runtime (the default; CLI: alter keys mint)
alter_ak_… (agent)AI agents using the Agent SDK classApp → API Keys, key type agent (CLI: alter keys mint --key-type agent)
alter_dk_… (derived)Short-lived, scope-narrowed sub-keys for plugins or tool callsProgrammatic only via app.keys.derive()
alter_key_… (legacy)Per-agent keys bound to one managed agentApp → Agent Identity → <agent> → API keys (CLI: alter agents mint-key)

Keys minted before the scoped formats also use the legacy alter_key_… prefix, and per-agent keys still mint with the legacy prefix today. Legacy keys keep working, but the prefix does not indicate whether the key is an app or an agent key.

Every key authenticates the same way — the SDK handles signing and presentation transparently. The wire protocol is identical; the difference is which principal the backend resolves the call to.

The default key for backend code that calls third-party APIs through Alter. One per app is enough for most products.

For PAT-authenticated CLI automation, the key routes enforce these scopes:

OperationPAT scope
List or show key metadatadashboard_keys:read
Create, rotate, or renamedashboard_keys:write
Revokedashboard_keys:admin

The PAT owner must still be a current organization admin to create or rotate a key. These dashboard scopes are separate from the app-key action scopes used by app.keys: derivation requires keys:derive, while programmatic rotation and revocation require keys:admin for the target key.

Open API Keys and select Create key. The plaintext is shown once. Store it in a secret manager and revoke if it’s lost.

To rotate without downtime:

  1. Mint a new key.
  2. Deploy it to the running service.
  3. After confirming the new key is in use (Audit Logs → Access & Requests → By Agent, then select the key-prefix chip), revoke the old one.

alter keys rotate performs the same exchange in one step: the new plaintext is returned once, and the old key remains valid for a 30-day overlap window unless it is revoked sooner. Programmatic app.keys.rotate(key_id=...) uses a configurable overlap of 0–30 days and defaults to 7 days.

API Keys → <key> → Revoke. Effective immediately. The next call with the revoked key fails with key_revoked (KeyRevokedError in both SDKs), and the key remains listed with a revoked status.

An agent can hold many API keys at once. Use this for:

  • Standalone agent processes — keys per process / pod / container.
  • Per-tenant agents — one tenant per agent, one key per tenant.
  • Rotation without downtime — same pattern as app keys, scoped to the agent.

Agent Identity → <agent> → API keys → Mint key. Plaintext shown once. Equivalent SDK call:

result = await app.agents.mint_key(agent_id=AGENT_ID)
print(result.api_key)

Each key has a key_prefix (the first N characters of the plaintext) shown in the UI; use it to identify keys in audit logs without exposing the secret.

Before hard-revoking a key, deprecate it first. A deprecated key still authenticates, but the SDK surfaces a deprecation warning every time the key is used. Watch logs for lingering callers, fix them, then revoke.

agents.revoke_key(). Terminal — the key never authenticates again.

The portal refuses to revoke a key that would leave the agent with zero active keys (raises LastActiveKeyError via SDK). Pass force=True to override, or mint a replacement key first.

For short-lived, scope-narrowed keys (handing access to a plugin, a tool call, a code sandbox):

sub_key = await app.keys.derive(
scopes=["grants:read"],
expires_in=3600, # one hour
)
print(sub_key.api_key)

The derived key intersects the parent key’s scopes with the requested scope set — it can only narrow, never broaden. Useful for handing the SDK to a less-trusted component without minting a long-lived agent.

Derived keys cannot be rotated. Derive a replacement from the parent key, then revoke the old derived key with await app.keys.revoke(key_id=KEY_ID).

For a single call site that should run with narrower scopes than the parent key, use with_constraints() instead of deriving a key:

limited = app.with_constraints(scopes=["grants:read"])
await limited.list_grants()

The returned SDK instance carries the narrowed scopes through to every request automatically. No key is minted; the constraint is in-process and disappears with the instance. with_constraints() also accepts an optional rule — a request rule, evaluated server-side, carried by every request the returned instance makes, that can only further restrict each one; pass scopes, rule, or both. See Scopes.

Every key lifecycle event (mint, deprecate, revoke, rotate) is in the audit log. Every API call carries the key ID; while the key metadata remains available, the audit view also resolves its name and prefix. Use the By Agent key-prefix chips to scope an investigation.

Report an issue with this page

Necessary

Required for sign-in, security, authorization, and remembering your choices.

Always active

Analytics

Helps us understand which product and documentation features are useful.

Performance diagnostics

Uses performance tracing and privacy-masked session replay to diagnose problems.

You can change these choices at any time from Cookie settings.