#Where is my API key?
It is in your project's .env, on the line anvil protect wrote there.
grep '^ANVIL_API_KEY=' .env
# ANVIL_API_KEY=anv_live_...
The key is the value after the = — anv_live_…. The variable name is not part of it.
# macOS — copy just the key to the clipboard
grep '^ANVIL_API_KEY=' .env | cut -d= -f2- | tr -d '\n' | pbcopy
#What it identifies
Every guarded call your app makes carries this key, and the key is what tells Anvil which workspace the call belongs to. That is why an action appears under one workspace and not another: the app reports to whatever ANVIL_API_KEY is in its own environment, not the one in the shell you are typing in.
#Why the dashboard asks for it
A confirmation gate stops a payment and waits for a person. Anvil emails that person only at an address the workspace has proven it owns — otherwise anyone signed in could point Anvil's sender at a stranger's inbox. Pasting the key anvil protect minted proves it, because only your workspace ever had that key.
Paste it into the Verify box on the dashboard's traffic strip. Pasting the whole ANVIL_API_KEY=anv_live_… line is fine — the name and any quotes are stripped for you.
#If you no longer have it
Keys are stored as a hash, so a key is shown once and can never be printed again. Mint a replacement and retire the old one in a single step:
anvil keys rotate --yes # replaces THIS shell's key, atomically
rotate prints the new key once; put it in your .env yourself and restart the app that reads it. Rotation is the safe move on a running service — the old key is retired only as the new one is minted.
To see what can reach your money path right now:
anvil keys list # prefix, label, created, last used; yours is flagged live·this
Keys are addressed by their prefix (anv_live_xxxxxxx), never by the secret, so list is safe to read out loud and safe to paste into a ticket.
#When a key is refused
- It is from another workspace. Check
anvil keys listfrom the project whose traffic you expect to see. - It was revoked or rotated away. A revoked key fails closed under enforce: the SDK raises
AnvilCredentialRevokedErrorand your side effect does not run. That is deliberate — a leaked credential is not an outage, so the fail-open knobs do not apply to it.
#Keep it out of your repo
anvil protect writes the key to .env and does not touch your .gitignore. Add .env to it yourself before your first commit. If a key does reach a log, a screenshot or a PR, rotate it — anvil keys rotate --yes — and the old one stops working on its next call.