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.
| Prefix | Used by | Where it’s minted |
|---|---|---|
alter_rk_… (runtime) | Backend services using the App SDK class | App → API Keys, key type runtime (the default; CLI: alter keys mint) |
alter_ak_… (agent) | AI agents using the Agent SDK class | App → 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 calls | Programmatic only via app.keys.derive() |
alter_key_… (legacy) | Per-agent keys bound to one managed agent | App → 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.
App keys
Section titled “App keys”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:
| Operation | PAT scope |
|---|---|
| List or show key metadata | dashboard_keys:read |
| Create, rotate, or rename | dashboard_keys:write |
| Revoke | dashboard_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.
Rotate
Section titled “Rotate”To rotate without downtime:
- Mint a new key.
- Deploy it to the running service.
- 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.
Revoke
Section titled “Revoke”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.
Per-agent keys
Section titled “Per-agent keys”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.
Deprecate (soft-revoke)
Section titled “Deprecate (soft-revoke)”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.
Revoke
Section titled “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.
Derived sub-keys
Section titled “Derived sub-keys”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).
Attenuating in-process
Section titled “Attenuating in-process”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.