keys
Recover from a leaked or expired project key — inspect metadata, rotate, or revoke
keys is how you recover from a leaked or expired project key, and how you change a key's scope. It has three subcommands — show, rotate, and revoke — and every one requires a JWT (an email/password login), because rotating or revoking a key is an account-level act a project key should not perform on itself. Run one under a project key and it exits 3 before any request, with a hint that depends on where the key came from: unset SOLWYN_API_KEY and log in, or log out and back in if the key is in the keychain.
Every project key carries a scope, full or read_only. A read-only key satisfies project-key reads but is refused by writes — budget check, budget confirm, record, notifications set — with a 403, the code read_only_key, exit 3, and a hint naming keys rotate --scope full. See Key scopes.
There is no keys create. A project's first key is minted by projects create; a replacement is minted by keys rotate. keys manages the lifecycle of an existing key — it does not add new ones.
keys show
Show the active key's metadata. It never reveals key material — only the prefix and lifecycle timestamps.
$ solwyn --project proj_0123456789abcdef01234567 keys show
Field Value
ID key_5f2a9c1e
Key prefix sk_proj_a1b2c3d4e5f67890
Name my-agent
Last used 2026-07-10T14:22:03Z
Expires -
Rotation grace until -
Created 2026-06-01T09:00:00Z
Scope fullThe Key prefix is sk_proj_ plus the first sixteen characters of the key — enough to identify it, never enough to use it. The CLI refuses to even parse a show response that contains key material.
| Contract | |
|---|---|
| Auth | JWT |
| Exit codes | 0 success · 1 generic/API · 2 usage · 3 auth · 5 not found |
| JSON schema | solwyn.keys-show.v1 |
keys rotate
Mint a replacement key and reveal it exactly once. The old key stays valid for a grace window so you can cut over without downtime.
solwyn --project <project_id> keys rotate [--grace-seconds INT] [--scope full|read_only] [--yes]| Option | Type | Default | Purpose |
|---|---|---|---|
--grace-seconds | integer 0–604800 | server default | Seconds the old key remains valid after rotation (0 through 604800 — up to seven days). |
--scope | full | read_only | keep current | Scope for the replacement key. Omit to carry the current key's scope over. |
| Contract | |
|---|---|
| Auth | owner/admin JWT (key.write) |
| Exit codes | 0 success · 1 generic/API · 2 usage or confirmation · 3 auth · 5 not found |
| JSON schema | solwyn.keys-rotate.v1 |
The replacement key is shown exactly once, in a panel below the metadata table. Store it in your OS keychain or secret manager before you close the terminal — it cannot be retrieved again. If you lose it, rotate again.
$ solwyn --project proj_0123456789abcdef01234567 keys rotate --grace-seconds 3600 --yes
Field Value
ID key_9d4b7a02
Key prefix sk_proj_9f8e7d6c5b4a3120
Rotation grace until 2026-07-11T15:00:00Z
Scope full
╭─ One-time replacement project key ─╮
│ sk_proj_9f8e7d6c5b4a3120… │
╰─────────────────────────────────────╯The panel prints the full key — 64 hexadecimal characters — shown here truncated. In JSON output the same value is the key field. Set --grace-seconds 0 to invalidate the old key the moment the new one is issued. The rotation request is never retried or replayed, so a rate limit or an expired login fails immediately rather than minting twice; a 409 means a rotation is already in progress, and a 410 means the key is already inactive — both exit 1 with a hint to inspect keys show first.
keys revoke
Hard-revoke a key without minting a replacement. Use this when a key is compromised and you have already rotated, or when retiring a key for good.
solwyn --project <project_id> keys revoke --key-id <id> [--yes]| Option | Type | Default | Purpose |
|---|---|---|---|
--key-id | string | required | Identifier of the key to hard-revoke. Never pass key material — only the identifier from keys show. |
| Contract | |
|---|---|
| Auth | owner/admin JWT (key.write) |
| Exit codes | 0 success · 1 generic/API · 2 usage or confirmation · 3 auth · 5 not found |
| JSON schema | solwyn.keys-revoke.v1 |
A successful revoke returns no body from the Cloud API; the CLI synthesizes the confirmation from the project and key ids.
$ solwyn --project proj_0123456789abcdef01234567 keys revoke --key-id key_5f2a9c1e --yes
Field Value
Project proj_0123456789abcdef01234567
Key ID key_5f2a9c1e
Revoked trueRotation and revocation display effects on stderr, then require confirmation or --yes. Without a TTY and without --yes, they exit 2 before HTTP; decline, EOF and Ctrl-C submit no write. Rotation reveals a replacement once and expires the old key after the chosen grace period (immediately for zero); revoke invalidates the target without replacement. Inspect keys show after an uncertain write before retrying. These writes stay CLI-only.
Related
- Authentication — where credentials are stored, how they resolve, and what
fullversusread_onlyallows projects create— mint a project's first key- Dashboard: API keys — the same rotate-with-grace and emergency revoke, from the browser
- Scripting — JSON envelopes and the exit-code contract