Playbook: ClickUp API Key Rotation
Service: ClickUp (https://app.clickup.com) — project management
Secret: clickup_clickup_api_key
SOPS file: secrets/art-agency.env.sops
Rotation frequency: 90 days (or immediately on suspected exposure)
Last rotated: 2026-06-27
Next due: 2026-09-27
What uses this credential
| Consumer | How | Effect if missing |
|---|---|---|
| Art Agency app | ClickUp API calls to manage tasks/projects for artwork orders | Task creation and status updates fail |
| n8n workflows (if any) | HTTP Request nodes calling ClickUp API | ClickUp automation stops |
Where stored
| Location | Key name | How to update |
|---|---|---|
secrets/art-agency.env.sops | clickup_clickup_api_key | SOPS write pattern |
Art Agency .env.local | clickup_clickup_api_key | Update manually (stale fallback only) |
Login credentials
- URL:
https://app.clickup.com/settings/apps - Email: radieu@gmail.com
- Auth: Google SSO or email/password
Automation status
Playwright-automatable — ClickUp API token management accessible via web UI without additional MFA.
Rotation steps
Option A — Playwright agent (preferred)
You are rotating clickup_clickup_api_key for the ClickUp project management service.
IMPORTANT: Never display any secret value in your response. Reference key names only.
1. Use Playwright to navigate to https://app.clickup.com/settings/apps
- Sign in with Google using radieu@gmail.com
- Find "API Token" section (may be under Settings → Apps → API)
- Click "Regenerate" or copy-then-regenerate to get new token
- Store new token in $env:NEW_KEY (starts with pk_; never print)
- Close the browser
2. Update secrets/art-agency.env.sops:
$env:SOPS_AGE_KEY_FILE = "C:\Users\konar\.age\p24-infra-keys.txt"
$plain = sops --decrypt --input-type dotenv --output-type dotenv secrets\art-agency.env.sops
$temp = "$PWD\secrets\art-agency-edit.env.sops"
$updated = $plain -replace "^clickup_clickup_api_key=.*", "clickup_clickup_api_key=$env:NEW_KEY"
[System.IO.File]::WriteAllText($temp, ($updated -join "`n") + "`n", [System.Text.UTF8Encoding]::new($false))
$enc = sops --encrypt --input-type dotenv --output-type dotenv $temp
[System.IO.File]::WriteAllText("$PWD\secrets\art-agency.env.sops", ($enc -join "`n") + "`n", [System.Text.UTF8Encoding]::new($false))
sops --decrypt --input-type dotenv --output-type dotenv secrets\art-agency.env.sops | Out-Null
if ($LASTEXITCODE -ne 0) { throw "SOPS corrupt — do NOT commit" }
[System.IO.File]::Delete($temp); $env:NEW_KEY = ""
3. Commit and PR:
git checkout -b fix/rotate-clickup-api-key origin/main
git add secrets/art-agency.env.sops
git commit -m "chore: rotate clickup_clickup_api_key (scheduled 90d rotation)"
git push -u origin fix/rotate-clickup-api-key
gh pr create --base main --title "chore: rotate ClickUp API key"
gh pr merge --merge --delete-branch
4. Append to docs/secrets-rotation-log.md:
| <YYYY-MM-DD> | clickup_clickup_api_key | scheduled 90d rotation | AI-agent | SOPS (art-agency) |
Option B — Manual (fallback)
Step 1 — Regenerate in ClickUp
URL: https://app.clickup.com/settings/apps
→ Log in → API Token → Regenerate → copy value (starts with pk_)
Step 2 — Store in .env.local then hand off to Claude:
Add to Art-Agency/.env.local (or d:\code_2026\p24-infra\.env.local):
clickup_clickup_api_key_NEW=<value>
Tell Claude "ClickUp key updated in .env.local" — Claude handles SOPS + PR.
Verification
$env:SOPS_AGE_KEY_FILE = "C:\Users\konar\.age\p24-infra-keys.txt"
$line = sops --decrypt --input-type dotenv --output-type dotenv secrets\art-agency.env.sops |
Select-String "^clickup_clickup_api_key="
$val = $line.ToString().Split('=',2)[1]
Write-Host "clickup_clickup_api_key length: $($val.Length)" # expected: > 20 (pk_ prefix)
# Quick API check
$env:K = $val
$r = Invoke-RestMethod "https://api.clickup.com/api/v2/user" `
-Headers @{ Authorization = $env:K }
Write-Host "ClickUp user: $($r.user.username)"
$env:K = ""; $env:SOPS_AGE_KEY_FILE = ""Escalation
| Symptom | Action |
|---|---|
| ClickUp UI has moved API token | Try https://app.clickup.com/settings/apps or Settings → Integrations → API |
| ”Regenerate” removes old token immediately | New token starts working right away; no dual-validity window |
| Art Agency app 401 after rotation | Check if art-agency.env.sops was deployed; restart Art Agency app or sync .env.local |
Prevention
- ClickUp API tokens do not expire but should be rotated on schedule.
- The
credential-rotation.ymlGH Actions workflow (Monday 06:00 UTC) checksnext_dueand opens ahuman-actionissue. - After rotation, update Last rotated and Next due at the top of this playbook.
Audit Log — Log to infra_operations
After this operation completes, log it to the infra_operations audit table.
Python (Linux server — bms-4, vps-i1, vps-h1, or similar):
import sys
sys.path.insert(0, '/opt/p24-infra')
from scripts.lib.log_op import log_op
log_op(
actor="claude", # "radieu" for manual human ops, "claude" for agent
op_type="credential_rotation",
resource="CLICKUP_API_KEY",
result="success", # "success" | "failed" | "skipped"
detail="Scheduled rotation — new ClickUp API key generated and SOPS updated",
env="vps-i1",
gh_issue=2730,
)PowerShell (Windows dev machine):
$env:SUPABASE_URL = (Get-Content "C:\code_2026\p24-infra\.env.local" | Select-String "^SUPABASE_URL=").ToString().Split("=",2)[1].Trim()
$env:SUPABASE_SERVICE_KEY = (Get-Content "C:\code_2026\p24-infra\.env.local" | Select-String "^SUPABASE_SERVICE_KEY=").ToString().Split("=",2)[1].Trim()
python -c "
import os, sys
sys.path.insert(0, 'C:/code_2026/p24-infra')
from scripts.lib.log_op import log_op
log_op('claude', 'credential_rotation', 'CLICKUP_API_KEY', 'success', 'Scheduled rotation — new ClickUp API key generated and SOPS updated', 'vps-i1')
"
$env:SUPABASE_URL = ''; $env:SUPABASE_SERVICE_KEY = ''