Headroom

Why Claude Code bills your API key instead of your plan

If ANTHROPIC_API_KEY is set, Claude Code can use it instead of your subscription and charge API rates. How the precedence works, how to spot it and how to unset it.

· 6 min read

If an ANTHROPIC_API_KEY environment variable is set where you run Claude Code, Claude Code can use that key instead of your Claude subscription, and you pay API rates instead of using your plan's included usage. In interactive sessions it does so once you have approved the key; with claude -p it always uses a key that is present. To spot it, run /status. To fix it, unset the variable, remove it from your shell profile and check /status again.

What Anthropic says

The Help Center states it directly: "If you have an ANTHROPIC_API_KEY environment variable set on your system, Claude Code will use this API key for authentication instead of your Claude subscription (Pro, Max, Ultra, Team, or Enterprise plans), resulting in API usage charges rather than using your subscription's included usage" (use Claude Code with your plan).

Subscriptions and API keys fail in different ways, which is why this can go unnoticed. A plan stops you at a limit. Anthropic describes API key billing as pay-as-you-go with "No hard stop; the account is charged for what it uses" (models, usage and limits). So a key that is quietly winning means you will not see limit messages, and you might not notice until a bill arrives or the key's Console balance runs out, which is the situation in Fix "Credit balance is too low".

The precedence order

When several credentials exist, Claude Code picks the first in this order, per the authentication docs:

  1. Cloud provider credentials, when CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX or CLAUDE_CODE_USE_FOUNDRY is set
  2. ANTHROPIC_AUTH_TOKEN
  3. ANTHROPIC_API_KEY
  4. apiKeyHelper
  5. CLAUDE_CODE_OAUTH_TOKEN
  6. Anthropic profile and federation credentials
  7. Subscription OAuth from /login, described as "the default for Claude Pro, Max, Ultra, Team, and Enterprise users"

Your subscription login is last. Anything set higher up the list, whether you meant it to be or not, takes priority. Running /login does not change that for an approved API key: Anthropic's error reference says such a key "takes precedence over your login, so /login doesn't replace it" (errors). The one entry /login does displace is CLAUDE_CODE_OAUTH_TOKEN: if you run /login while it is set, Claude Code switches the current session to the new login, and new sessions go back to the token until you remove the variable.

The one-time approval

In interactive mode, Claude Code does not switch silently. It asks once whether to use the key and remembers the answer. You can change that later with the "Use custom API key" toggle in /config, which only appears while ANTHROPIC_API_KEY is set in your environment. So the usual route to a surprise bill is: a key was present once, you said yes (or clicked through), and the choice stuck.

In non-interactive mode there is no prompt. Anthropic: "In non-interactive mode (-p), the key is always used when present." A script or CI job that runs claude -p with a key in its environment bills that key every time, even when you are signed in with a plan. Without a key, the same command draws on your plan; see how claude -p interacts with subscription limits.

How to spot it

Run /status in Claude Code. It opens Settings on the Status tab, "showing version, model, account, and connectivity". When a login and an API key are both configured, /status marks the credential that isn't in use. If your subscription login is the one marked as not in use, or there is an API key row that is not marked that way, the key is the active credential.

Other signs:

  • A notification right after you sign in. Anthropic's API key article says Claude Code shows one when both credentials are active, "alerting you to the potential for unexpected API charges".
  • "Credit balance is too low" on a subscription, which Anthropic's error reference ties to an approved key routing requests through a Console account.
  • "API Error: Request rejected (429)", which means the rate limit configured for an API key, Amazon Bedrock project or Google Cloud project, not a subscription limit. Anthropic's first suggested step is /status, and it notes that "A stray ANTHROPIC_API_KEY in your environment can route requests through a low-tier key instead of your subscription."
  • "Invalid API key · Fix external API key", which means the key Claude Code is sending was rejected or blocked.
  • Console billing activity you did not expect, or no session or weekly limit messages when you would expect them.

Users have reported this in different forms: a key in a project .env file used instead of a Max plan (GitHub issue #58083), and /login reporting success while an approved key still took priority (#108904). These are user reports.

How to fix it

Anthropic's guide to API key environment variables starts with the current shell:

unset ANTHROPIC_API_KEY

That only lasts for the current terminal. To stop the key coming back, find where it is set and delete that line. A quick search of the usual zsh and bash profiles:

grep -n ANTHROPIC_API_KEY ~/.zshrc ~/.zprofile ~/.bash_profile 2>/dev/null

Then finish the job:

  • Check project .env files and anything that loads them into your shell. Anthropic's errors page names direnv, dotenv shell plugins and IDE terminals as tools that "can load a stale key from a .env file in your project without you setting it explicitly."
  • If you approved the key earlier, turn off "Use custom API key" in /config.
  • Open a new terminal, start Claude Code and run /status to confirm the subscription login is in use.

Also look for the other entries in the precedence list. ANTHROPIC_AUTH_TOKEN or a cloud provider variable can win over a subscription just as a key can, and apiKeyHelper is a settings entry rather than an environment variable, so check your settings files for it.

Where the variables apply

Anthropic says apiKeyHelper, ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN apply to the CLI and the surfaces that wrap it, "including the VS Code extension, the Agent SDK, and GitHub Actions." Claude Desktop and cloud sessions do not read these variables; they use OAuth. So the same Mac can bill an API key from the terminal while the desktop app bills your plan.

Doing it on purpose

Nothing is wrong with using an API key for automation. Anthropic's preferred route for third-party tools is API key authentication through the Claude Console or a supported cloud provider (login help). The point is that it should be a choice. If you want both, keep the key out of your interactive shell and give the automation its own environment. Max, Ultra and Team also include monthly Claude Platform credits, which can cover claude -p only when it runs with a key from the Console organization you linked; see monthly API credits vs usage credits.

For fresh sign-ins, claude auth login has --claudeai (Claude subscription, the default) and --console (Anthropic Console, API usage billing), per claude auth help login on Claude Code 2.1.322.

Checking the plan side

Once the key is gone, confirm your plan is the one being used. /usage shows plan limits and resets. Headroom is a free Mac menu bar app that shows session and weekly use for each Claude Code account signed in on your Mac. If your plan's meters never move while you work, that is a hint that requests are going somewhere else. It does not track API key or Console billing itself, and it never sends a prompt. It is independent, not made or endorsed by Anthropic. Get it at headroom.everydaymactools.com.