Reference
alter keys
Mint, rotate, revoke, and rename runtime API keys.
Runtime API keys authenticate application code against Alter. These commands manage the keys for one app.
alter keys list [--status active|revoked] [--limit ...] [--offset ...]alter keys statistics [--output json|jsonl|table]alter keys mint --name <name> --scopes <list> [--key-type ...] [...]alter keys show --key <key-id>alter keys rotate --key <key-id> [--scopes ...]alter keys revoke --key <key-id> [--force] [--yes]alter keys rename --key <key-id> --name <name>All commands are app-scoped — pass --app <id> (or the app’s name), or link a workspace / set ALTER_APP_ID. list / show / statistics need dashboard_keys:read; mint / rotate / rename need dashboard_keys:write; revoke needs dashboard_keys:admin.
| Flag | Default | Description |
|---|---|---|
--status <status> | all | Client-side filter on the fetched page: active means revoked_at is null (including rotated keys still in grace); revoked means it is set. |
--limit <n> | 200 | Page size (1–1000). |
--offset <n> | 0 | Pagination offset. |
alter keys list --status activeAll output formats emit the filtered current-page rows as an array/row stream, not the pagination envelope. Filtering happens after the page is fetched.
The table includes a RATE LIMIT column showing the ceiling each key is
actually held to and which layer produced it — 1000 (key) for a per-key value
chosen at mint time, 1000 (org) for the organization’s per-key maximum, and
1000 (platform) for the platform default. The distinction matters when
capacity-planning: a platform default can move, a per-key value cannot. A —
means the backend did not report a ceiling — unknown, never unlimited.
500 (?) means the backend reported the effective ceiling but omitted or used
an unrecognized source; the number remains usable while its controlling layer
is unknown.
statistics
Section titled “statistics”Read-only quota summary for the app’s keys — active, rotated_in_grace, total, and max_allowed. Useful for a CI preflight before minting (e.g. fail the job if active is near max_allowed).
| Flag | Default | Description |
|---|---|---|
--output <format> | json | json, jsonl, or table. |
alter keys statistics --output tableMint a new scoped key. --name and --scopes are required unless you supply a full JSON body with --input.
| Flag | Required | Description |
|---|---|---|
--name <name> | yes | Display name. |
--scopes <list> | yes | Comma-separated Alter scopes (e.g. grants:read,agents:read). |
--key-type <type> | no | runtime (default — an SDK key, alter_rk_…) or agent (an agent-typed alter_ak_… key bound to no managed agent: it cannot reach grants bound or delegated to a named agent and does not satisfy key_type: agent in ALTER_INTEGRATION.md — use alter agents create or alter agents mint-key for a named agent). |
--cidr <list> | no | Comma-separated CIDR allowlist. Catch-all ranges are rejected: a single /0, a split-range set whose union covers a whole address family (e.g. 0.0.0.0/1,128.0.0.0/1), and an entry covering the entire IPv4-mapped-IPv6 block (::ffff:0.0.0.0/96). For an unrestricted key, omit the flag entirely. |
--rate-limit-rpm <n> | no | Per-key requests-per-minute cap (1–100000). When the organization sets a per-key maximum, a higher value is rejected at mint time. Omitted, the organization’s per-key maximum becomes this key’s limit — it replaces the platform default rather than capping it, so the effective limit can be well above 1,000. With no per-key value and no organization maximum, the platform default of 1,000 requests/minute applies. See Errors for the full precedence table. |
--expires-in <duration> | no | Relative expiry, e.g. 30d, 12h, 5m. The backend samples the start time, so client-clock skew cannot push an exact-maximum request over the ceiling. Mutually exclusive with --expires-at. Omit both expiration flags to use the organization’s finite default TTL. |
--expires-at <iso> | no | Absolute ISO 8601 expiry. Mutually exclusive with --expires-in; the organization’s maximum TTL still applies. |
--input <path> | no | JSON body from a file (@path) or stdin (-); replaces the per-field flags. expires_in is a server-relative lifetime in seconds and is mutually exclusive with the absolute expires_at. Omitting both applies the organization’s finite default TTL. |
alter keys mint --name "prod-worker" --scopes grants:read,agents:read --expires-in 90dCapture the secret from the plain_key field in the same pipeline, so it never lands in the terminal or shell history:
# Only the secret, as a bare string — pipe it straight into a secret storealter keys mint --name ci-deploy --scopes grants:read --output json | jq -r '.plain_key'
# Or narrow the JSON to that one fieldalter keys mint --name ci-deploy --scopes grants:read --output json --fields plain_keyEvery app key expires. If neither expiration flag is supplied, the backend applies the organization key policy’s Default key TTL (days) (90 days by default). Explicit values are rejected when they exceed Maximum key TTL (days) (365 days by default). The CLI has no unlimited-key flag.
alter keys show --key <key-id>rotate
Section titled “rotate”Issue a new secret for an existing key. The new plaintext is returned once; the old key enters a grace period until it’s revoked. An app-key successor receives a fresh lifetime from the organization’s current finite default. --scopes optionally changes the scope set (defaults to the current one). A key created before the September 2026 key-security upgrade (including every historical no-expiration key) can no longer authenticate and cannot be rotated — mint a new key instead; see Keys created before the September 2026 upgrade.
alter keys rotate --key <key-id>revoke
Section titled “revoke”Revoke a key immediately. This cascades to any derived keys. Revocation is recoverable — mint a new key — so the CLI asks a simple y/N (skip with --yes).
--force overrides the last-active-key guard, which otherwise blocks revoking the last active key on an app or an agent (whatever authenticates with that key stops working until a fresh key is minted). Use it deliberately — for example to clear a key whose plaintext was never captured.
alter keys revoke --key <key-id>alter keys revoke --key <key-id> --yes --force # CI, deliberaterename
Section titled “rename”Change a key’s display name. Cosmetic only — it does not rotate the secret.
alter keys rename --key <key-id> --name "prod-worker-east"Recipes
Section titled “Recipes”Mint the Developer Portal’s Backend service template from the CLI
alter keys mint --name backend-service \ --scopes grants:write,providers:read,tokens:retrieve,proxy:execute,connect:initiate,audit:emitThis is the CLI equivalent of choosing Backend service under App → API Keys → Create key. OAuth Connect requires connect:initiate and grants:write together; providers:read powers SDK provider discovery, and audit:emit lets direct SDK calls record provider outcomes.
Rotate a key without downtime
# 1. Rotate — a new plaintext is printed once; the old secret keeps# working during its grace window.alter keys rotate --key <key-id># 2. Roll the new value out everywhere and confirm healthy traffic.# 3. Revoke the superseded key once nothing depends on it.alter keys revoke --key <key-id> --yesMint a short-lived key for a CI job
alter keys mint --name ci-deploy --scopes grants:read,agents:read --expires-in 1hRelated
Section titled “Related”alter agents— managed-agent identities and their own keys- API keys, Scopes