BUZZ AI Gateway
HomeBlog › ANTHROPIC_BASE_URL Reference

How to Point Claude Code at a Custom Endpoint: Complete ANTHROPIC_BASE_URL Reference

You opened a terminal, ran claude, and it talked to api.anthropic.com. That is the default, and it is fine until the day it is not. Maybe a gateway sits in front of the model for cost or compliance reasons. Maybe you are running an internal proxy that scrubs PII before it leaves the building. Maybe you just want to A/B test two endpoints from the same machine. ANTHROPIC_BASE_URL is the lever that lets you do all of that without rebuilding the CLI or touching a single project file.

Reference guide · Claude Code custom endpoint · ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN

What is ANTHROPIC_BASE_URL

ANTHROPIC_BASE_URL is the environment variable that tells Claude Code (and the Anthropic SDKs underneath it) which HTTPS host to send Messages API requests to. The CLI joins this base with paths such as /v1/messages and /v1/models, so the value should be a host root like https://buzzai.cc, not a full path. The default, when the variable is unset, is https://api.anthropic.com.

The variable has been part of the Anthropic SDK contract since the early Python and JavaScript releases. Claude Code inherits it automatically because the CLI is built on the JavaScript SDK. That makes claude code base_url configuration a no-code change: the CLI never asked which endpoint you wanted, it just reads what is in the environment.

The typical reasons to override it:

The contract is intentionally narrow. The variable changes only the destination host. It does not change the request body, the model identifier, the streaming protocol, or the response shape. If a gateway is well-behaved, swapping ANTHROPIC_BASE_URL is the entire diff.

Two configuration methods

There are two supported places to put the value: a shell export, or the Claude Code settings.json file. Both work. Picking the right one is a matter of scope and persistence.

AspectShell exportsettings.json
ScopeCurrent shell or whatever inherits its envAll Claude Code sessions for the user (or project)
PersistenceUntil the shell exits, unless written to a profile filePersistent across sessions
Switching endpointsTrivial: unset and re-exportEdit and save the JSON
Per-project overrideRun claude from a directory with the right env loaded.claude/settings.json in the project root
PrecedenceHigher: shell env winsLower: only used if env is unset
Best forTesting, side-by-side comparison, ephemeral sessionsLong-lived setup on a developer machine or CI runner

Most teams end up using both. The settings.json file holds the steady-state configuration for the gateway in daily use, and a shell export takes over when someone wants to test a different endpoint without disturbing anyone else.

macOS / Linux setup

On macOS and any Linux distribution, the workflow is identical. The only choice is whether your interactive shell is bash or zsh. Modern macOS ships with zsh by default; most Linux distributions still default to bash. Check yours with echo $SHELL.

The minimum setup is two exports: the base URL and the auth token.

# ~/.zshrc or ~/.bashrc
export ANTHROPIC_BASE_URL="https://buzzai.cc"
export ANTHROPIC_AUTH_TOKEN="buzz-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Optional: unset any first-party key that might shadow the token
unset ANTHROPIC_API_KEY

Reload the shell so the exports take effect:

# zsh
source ~/.zshrc

# bash
source ~/.bashrc

# Verify
echo "$ANTHROPIC_BASE_URL"
echo "${ANTHROPIC_AUTH_TOKEN:0:8}..."

The masked print is a small habit worth picking up. It confirms the variable is set without committing the full token to scrollback or to a recorded terminal session. The :0:8 bash and zsh substring syntax shows the first eight characters and nothing else.

From here, launch the CLI:

claude
# or, for a one-off prompt
claude --print "What is the capital of Iceland?"

If you want a per-project override that does not pollute your shell profile, use a .envrc with direnv, or a .env file consumed by your task runner. Both keep the override local to the directory while leaving the global shell untouched.

Fish shell

For fish users the syntax is different but the variables are the same:

set -Ux ANTHROPIC_BASE_URL "https://buzzai.cc"
set -Ux ANTHROPIC_AUTH_TOKEN "buzz-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
set -e ANTHROPIC_API_KEY

The -U flag persists the value across fish sessions. The -x flag exports it to child processes, which is what Claude Code needs.

Windows setup

Windows offers two reasonable shells: PowerShell (recommended for new setups) and Command Prompt. Both can configure the same variables; only the syntax differs.

PowerShell, current session

# Sets the variables for this PowerShell process only
$env:ANTHROPIC_BASE_URL = "https://buzzai.cc"
$env:ANTHROPIC_AUTH_TOKEN = "buzz-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Remove-Item Env:ANTHROPIC_API_KEY -ErrorAction SilentlyContinue

# Verify
echo $env:ANTHROPIC_BASE_URL
echo $env:ANTHROPIC_AUTH_TOKEN.Substring(0, 8)

claude --print "ping"

PowerShell, persistent (user-scoped)

# Persists to the user environment; takes effect in new shells
[Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", "https://buzzai.cc", "User")
[Environment]::SetEnvironmentVariable("ANTHROPIC_AUTH_TOKEN", "buzz-xxxx...", "User")
[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $null, "User")

Open a fresh PowerShell window after running these. The current process keeps the old environment because Windows only re-reads user variables on shell start.

Command Prompt

:: Current cmd session only
set ANTHROPIC_BASE_URL=https://buzzai.cc
set ANTHROPIC_AUTH_TOKEN=buzz-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
set ANTHROPIC_API_KEY=

:: Persistent (user-scoped); requires a new cmd window to apply
setx ANTHROPIC_BASE_URL "https://buzzai.cc"
setx ANTHROPIC_AUTH_TOKEN "buzz-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Avoid pasting the raw token into a CI log. PowerShell's Read-Host -AsSecureString is a cleaner pattern when scripting a setup that other people will inherit.

settings.json configuration

For a configuration that survives across sessions, machines synced via dotfiles, and per-project overrides, put the values in Claude Code's settings.json. The CLI reads two files, in order, and merges them:

The structure is JSON with an env block. Anything inside env is exported into the CLI's process environment before it makes a request, so it is functionally equivalent to a shell export but stored on disk.

{
  "env": {
    "ANTHROPIC_BASE_URL": "https://buzzai.cc",
    "ANTHROPIC_AUTH_TOKEN": "buzz-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  },
  "model": "claude-opus-4-8",
  "permissions": {
    "allow": ["Read", "Edit", "Bash(git status)"]
  }
}

A per-project override looks the same, but lives at ./.claude/settings.json:

{
  "env": {
    "ANTHROPIC_BASE_URL": "https://internal-proxy.example.local",
    "ANTHROPIC_AUTH_TOKEN": "internal-team-token-xxxx"
  },
  "model": "claude-sonnet-4-6"
}

Two practical notes. First, do not commit project settings.json with a real token; instead, commit a settings.json.example and add the real file to .gitignore. Second, environment variables defined in your shell take precedence over settings.json, which is what you want when you need to temporarily override the saved configuration.

ANTHROPIC_AUTH_TOKEN vs ANTHROPIC_API_KEY

This is the single most common source of confusion when migrating Claude Code to a custom endpoint, so it deserves its own section.

The two variables look interchangeable. They are not. They produce different HTTP headers, and the wrong one against the wrong endpoint produces a 401 with a misleading message.

VariableHTTP header sentUse with
ANTHROPIC_API_KEYx-api-key: <value>First-party api.anthropic.com
ANTHROPIC_AUTH_TOKENAuthorization: Bearer <value>Custom endpoints, gateways, proxies

The historical reason: Anthropic's first-party API uses x-api-key, which predates the OAuth-style Bearer pattern that has since become the norm for HTTP APIs. Most gateways speak Bearer because that is what their auth layer (or upstream identity provider) expects. ANTHROPIC_AUTH_TOKEN exists specifically so that Claude Code can talk to those endpoints without the SDK forcing the legacy header.

The rule of thumb:

If both variables are set, behavior depends on the SDK version, but the safe pattern is to set only the one you need and explicitly unset the other. That eliminates an entire class of "it works on my machine" bugs.

Verifying the switch works

Configuration that you cannot verify is configuration you do not trust. Three checks, in order of decreasing convenience:

1. Run the CLI in debug mode

claude --debug --print "Say hi" 2>&1 | grep -i "base\|host\|http"

Debug output prints the resolved base URL the SDK is about to use. If you see https://buzzai.cc in the trace and a 200 from a request to /v1/messages, the configuration is live.

2. Curl the endpoint directly

Skip the CLI entirely and reproduce the request shape with curl. This isolates whether a problem is in the CLI or in the endpoint.

curl -sS https://buzzai.cc/v1/messages \
  -H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-4-8",
    "max_tokens": 64,
    "messages": [{"role": "user", "content": "Reply with the single word: pong."}]
  }' | jq '.content[0].text, .usage'

A success returns the model's text and a usage object with input_tokens and output_tokens. A failure returns an error envelope whose type field tells you exactly what to fix (authentication_error, not_found_error, invalid_request_error).

3. Probe the model list

Many gateways implement /v1/models. A quick GET confirms reachability and authentication independent of any specific model:

curl -sS https://buzzai.cc/v1/models \
  -H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN" | jq '.data[].id' | head -20

If the same curl works but the CLI does not, the problem is environment plumbing, not the endpoint. Check that the variables are exported (not just set) and that the shell you ran claude from is the one with the exports loaded.

4. Confirm from inside an SDK call

For applications using the Anthropic Python or Node SDKs, the same variables drive the client. A four-line script confirms the SDK and CLI agree:

# Python
import anthropic, os
client = anthropic.Anthropic()  # reads ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN
print("base:", client.base_url)
print(client.messages.create(
    model="claude-opus-4-8",
    max_tokens=64,
    messages=[{"role": "user", "content": "ping"}],
).content[0].text)
// Node
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // reads env vars
console.log("baseURL:", client.baseURL);
const msg = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 64,
  messages: [{ role: "user", content: "ping" }],
});
console.log(msg.content[0].text);

If the printed base URL is the gateway and the request returns a sensible reply, every layer is consistent.

Common errors

Five recurring failure modes, with the one-line fix for each.

1. 401 Unauthorized after switching to a gateway

Cause: ANTHROPIC_API_KEY is set with a gateway token, so the CLI sends x-api-key instead of Authorization: Bearer. Fix: unset ANTHROPIC_API_KEY and use ANTHROPIC_AUTH_TOKEN instead.

2. 404 Not Found on /v1/messages

Cause: ANTHROPIC_BASE_URL includes a path, for example https://buzzai.cc/v1. The SDK appends its own path on top. Fix: set the base to the host root only, https://buzzai.cc, no trailing path and no trailing slash.

3. CLI keeps hitting api.anthropic.com despite the export

Cause: the variable was set in one shell but claude was launched from another (different terminal app, different multiplexer pane, different IDE process). Fix: verify with printenv ANTHROPIC_BASE_URL in the exact shell that runs the CLI; restart the IDE or terminal to inherit fresh values.

4. SSL or TLS handshake failure

Cause: corporate proxy intercepting outbound HTTPS without a trusted root certificate. Fix: add the proxy's CA to the system trust store, or set NODE_EXTRA_CA_CERTS=/path/to/ca-bundle.pem for the Claude Code process.

5. OAuth login keeps overriding the token

Cause: a prior claude login session stored credentials that the CLI prefers over ANTHROPIC_AUTH_TOKEN when pointed at api.anthropic.com. Fix: run claude logout, then re-run with the env vars set so the CLI uses the token path exclusively.

FAQ

What does ANTHROPIC_BASE_URL do in Claude Code?

It tells Claude Code which HTTPS endpoint to send Messages API requests to. The default is https://api.anthropic.com. Setting it redirects every model call without changing your code or your prompts. Always set it to a host root, not a full path; the CLI appends paths like /v1/messages itself.

What is the difference between ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY?

ANTHROPIC_API_KEY goes out as x-api-key and is intended for first-party Anthropic. ANTHROPIC_AUTH_TOKEN goes out as Authorization: Bearer and is intended for custom endpoints. Setting the wrong one against the wrong endpoint produces a 401. When pointing at a gateway, set ANTHROPIC_AUTH_TOKEN and unset ANTHROPIC_API_KEY.

Where is the Claude Code settings.json file?

Globally at ~/.claude/settings.json on macOS and Linux, and at %USERPROFILE%\.claude\settings.json on Windows. A project-level file at ./.claude/settings.json takes precedence when you launch the CLI inside that directory. Both files accept an env block that mirrors shell environment variables.

Should I use settings.json or a shell export?

Use settings.json for the steady-state configuration that should persist across sessions and machines. Use shell exports for ephemeral overrides, A/B testing, or CI runs that should not mutate global state. Shell environment variables take precedence when both are present.

How do I verify the custom endpoint is in use?

Run claude --debug and look at the resolved base URL in the trace. As a second check, replicate the request with curl against /v1/messages using the same token. If both succeed, the CLI configuration matches what the network is doing. If only curl succeeds, the variable is not reaching the CLI process.

Does ANTHROPIC_BASE_URL work with the Anthropic Python and Node SDKs?

Yes. Both SDKs read the variable on client construction. You can also pass base_url (Python) or baseURL (Node) directly to the constructor, which overrides the env. Claude Code uses the JavaScript SDK internally, so the same variable controls both surfaces.

Why do I get 401 Unauthorized after switching endpoints?

The wrong credential variable is the usual culprit. A gateway token in ANTHROPIC_API_KEY goes out as x-api-key, which the gateway does not recognize. Move it to ANTHROPIC_AUTH_TOKEN and unset the other variable. If both look right, double-check that the value has no trailing newline (a common copy-paste artifact).

Can I keep using Claude Code's OAuth login while overriding the base URL?

No. The OAuth flow is bound to api.anthropic.com. When the base URL points elsewhere, the stored OAuth credentials will not authenticate. Run claude logout and authenticate via ANTHROPIC_AUTH_TOKEN instead. Switching back is a matter of unsetting the variables and signing in again.

Try BUZZ AI Gateway

Once ANTHROPIC_BASE_URL is wired up, the next question is what to point it at. BUZZ AI Gateway is a transparent forwarder for Claude (plus GPT, Gemini, and Grok with the same key), zero-retention by default, with discounted per-token rates that float with upstream pricing. Existing Claude Code projects work after a single export. Live rates at buzzai.cc/api/pricing, model list at buzzai.cc/models, one-line installer at buzzai.cc/sh/claudecode.sh.

Published: 2026-05-26
Last reviewed: 2026-05-26