Skip to content

Connect Claude Code to an LLM gateway

Check whether your admin already pointed Claude Code at the company gateway, or set the base URL and credential yourself, test it and fix common errors.

If your company runs an LLM gateway, Claude Code should talk to it with a credential the company issued rather than your personal claude.ai login. This page is for the developer at the keyboard. First check whether it is already set up for you; if it is not, configure it yourself in about five minutes.

Admins deploying the gateway want Roll out an LLM gateway. Gateway operators want the compatibility guide.

Is it already configured?

Admins can push the gateway address and credential through managed settings, device management or an apiKeyHelper. Check before you change anything:

  1. Run claude. If you land on the login screen rather than a session, nobody distributed a gateway credential. Skip to configuring it yourself.
  2. Run /status. It opens on the Status tab. Look for:
    • an Anthropic base URL line. It only appears when a gateway address is set. No line means you are not routed through the gateway.
    • an Auth token or API key line naming ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY or an apiKeyHelper. If you see a Login method line naming a claude.ai account instead, the credential is missing and you should set it yourself.
  3. Send a prompt. A normal reply means you are done.

If both status lines look right but prompts fail, go to troubleshooting.

Configure it yourself

Ask your gateway team for two things: the gateway's base URL, and a credential (either a fixed key or token, or a command that prints one).

Pick the credential variable

Each option puts the credential in a different HTTP header, and a credential in a header the gateway does not read fails with 401.

What the gateway team saidVariableHeader sent
"Bearer token" or "Authorization header"ANTHROPIC_AUTH_TOKENAuthorization: Bearer ...
"API key" or "x-api-key"ANTHROPIC_API_KEYx-api-key: ...
The credential rotates or lives in a vaultapiKeyHelper settingBoth headers

If nobody told you, start with ANTHROPIC_AUTH_TOKEN and switch if the test below returns 401.

Set the base URL and credential

For a first attempt, export the values in your shell so you can test before persisting anything. The values here are invented; use your own.

export ANTHROPIC_BASE_URL=https://ai-proxy.acme-retail.co.uk
export ANTHROPIC_AUTH_TOKEN=gw_live_7c2f91

In PowerShell:

$env:ANTHROPIC_BASE_URL = "https://ai-proxy.acme-retail.co.uk"
$env:ANTHROPIC_AUTH_TOKEN = "gw_live_7c2f91"

Exports only reach that terminal and programs started from it; an editor launched from the dock will not see them. Add them to ~/.zshrc, ~/.bashrc or your PowerShell $PROFILE to make them stick. Shell exports also do not reliably reach background agents hosted by the supervisor (see Agent view), so use a settings file for anything that must always route through the gateway.

Once it works, move the values into the env block of a settings file:

  • ~/.claude/settings.json (Windows: %USERPROFILE%\.claude\settings.json) applies to every project.
  • .claude/settings.local.json applies to one project. Claude Code adds it to your global gitignore when it writes a setting there itself; if you create it by hand, gitignore it first.
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://ai-proxy.acme-retail.co.uk",
    "ANTHROPIC_AUTH_TOKEN": "gw_live_7c2f91"
  }
}

Warning: Never put a credential in a project's .claude/settings.json. That file is committed and everyone who clones the repo gets it.

If the shell and a settings file both set the same variable, the settings file wins. /status shows which values are in force.

Test the connection

Before opening Claude Code, hit the gateway directly with a one-token request. A failure here is about the gateway or the credential, not your Claude Code set-up. This uses the shell exports, so keep them set even if you have also written a settings file.

curl -sS -w '\nHTTP %{http_code}\n' "$ANTHROPIC_BASE_URL/v1/messages" \
  -H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  --data '{"model":"claude-sonnet-4-6","max_tokens":1,"messages":[{"role":"user","content":"ping"}]}'

For an x-api-key gateway, swap the Authorization line for -H "x-api-key: $ANTHROPIC_API_KEY". In PowerShell, Invoke-RestMethod -Method Post with a -Headers hashtable does the same job.

Reading the result:

  • JSON beginning {"id":"msg_ with a content array: the URL and credential work.
  • An error about an unknown model: also fine. The gateway authenticated you before rejecting the model name.
  • 401: the credential was refused. If you guessed the variable, switch to the other one and retry.

Then start claude from the same shell, send a message and run /status. The Anthropic base URL line should show the gateway, and the Auth token or API key line should name the variable you set.

When you also have a claude.ai login

A gateway credential variable outranks a saved claude.ai login or Console key. The login stays on disk, unused, and comes back if you unset the variable. ANTHROPIC_AUTH_TOKEN takes over immediately; ANTHROPIC_API_KEY asks you once, in interactive mode, to approve it. If startup warns that two credential sources are active, run /logout to keep only the gateway credential, or unset the variable to go back to the login.

Other surfaces

The CLI reads the variables and settings files above. Everything else differs.

VS Code extension

Put the variables in VS Code's own user settings (run Preferences: Open User Settings (JSON)) under claudeCode.environmentVariables. The extension checks credentials from this setting before it launches; values in ~/.claude/settings.json reach the spawned process but not that login check.

{
  "claudeCode.environmentVariables": [
    { "name": "ANTHROPIC_BASE_URL", "value": "https://ai-proxy.acme-retail.co.uk" },
    { "name": "ANTHROPIC_AUTH_TOKEN", "value": "gw_live_7c2f91" }
  ]
}

See VS Code for the rest of the extension's settings.

Desktop app

The desktop app ignores ANTHROPIC_BASE_URL and settings.json. It reads its own third-party inference configuration instead:

  • Pushed by your admin. If the organisation deployed it, the app routes through the gateway with no action from you.
  • Set locally. Use Help, then Troubleshooting, then Enable Developer Mode. The app restarts with a Developer menu; choose Developer, then Configure Third-Party Inference, and enter the gateway URL. An admin-pushed configuration overrides this and makes the form read-only.

While a gateway configuration is active, Anthropic-hosted cloud environments are not offered and Remote Control is unavailable. SSH sessions are in beta with a gateway and need Claude Desktop v1.40609.0 or later. They are off until hosts are listed in the sshHostAllowlist key, and because the remote machine connects to the gateway itself, a gateway on your laptop's localhost will not work. A Gateway was unreachable message means the app could not reach the base URL at startup; run the curl test.

GitHub Actions

The GitHub action reads ANTHROPIC_BASE_URL and ANTHROPIC_CUSTOM_HEADERS from the workflow env, and you pass the credential as the anthropic_api_key input, which the action exports as ANTHROPIC_API_KEY (so it travels as x-api-key).

For a bearer-token gateway, the action does not read ANTHROPIC_AUTH_TOKEN on its own but does insist on anthropic_api_key, CLAUDE_CODE_OAUTH_TOKEN or workload identity federation before launching. So pass the same secret twice:

env:
  ANTHROPIC_BASE_URL: https://ai-proxy.acme-retail.co.uk
  ANTHROPIC_AUTH_TOKEN: ${{ secrets.AI_PROXY_TOKEN }}

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.AI_PROXY_TOKEN }}

The env variable puts the token in Authorization; the input satisfies the launch check and its x-api-key copy is ignored. For an x-api-key gateway, drop the ANTHROPIC_AUTH_TOKEN line.

Agent SDK

The Agent SDK has no gateway options; it hands environment variables to the Claude Code process it spawns via an env option. The two languages differ:

  • TypeScript: setting options.env replaces the whole environment, so spread process.env into it.
  • Python: ClaudeAgentOptions(env=...) is merged over the inherited environment, so gateway variables in the parent process carry through.
const run = query({
  prompt: "Summarise yesterday's failing tests",
  options: {
    env: { ...process.env, ANTHROPIC_BASE_URL: proxyUrl, ANTHROPIC_AUTH_TOKEN: proxyToken },
  },
});

Slack, cloud sessions, Remote Control and voice

Claude Code in Slack and cloud sessions are not part of a gateway deployment, and gateway variables set in a cloud environment's configuration are not applied. If traffic must stay on the gateway, do not enable these for those users.

Remote Control and voice dictation need a claude.ai identity, so both are unavailable while ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN or an apiKeyHelper is active. Remote Control is additionally blocked whenever ANTHROPIC_BASE_URL points at a non-Anthropic host (since v2.1.196). To get them back, log in with claude.ai and unset the credential (voice) or the credential plus ANTHROPIC_BASE_URL (Remote Control). The Remote Control section of claude doctor says what is blocking it.

Optional extras

Only set these if your admin asks, your network restricts egress, or the troubleshooting table points you here.

Extra headers

Some gateways want a tenant or routing header alongside the credential. Set ANTHROPIC_CUSTOM_HEADERS with one Name: Value per line; in JSON, separate pairs with \n:

{
  "env": {
    "ANTHROPIC_CUSTOM_HEADERS": "X-Cost-Centre: platform\nX-Region: uk"
  }
}

Headers like these count as headers needing approval under server-managed settings, and when they come from a project settings file Claude Code applies them under the usual rules for project env values.

Gateway models in the picker

Set CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1 and Claude Code asks the gateway for its model list at startup and adds those names to /model. Each shows the gateway's description, or From gateway if none is supplied. A modelPicker lineup with replaceBuiltInOptions hides discovered names too, though the model already in use keeps its row. To check discovery ran, start claude --debug and look for [gatewayDiscovery] lines in ~/.claude/debug/<session-id>.txt; it logs the count on first success and again only when the list changes.

Rotating credentials with apiKeyHelper

apiKeyHelper is a command whose standard output is the credential. Use it when keys expire or come from a vault or SSO tool. It must print nothing except the key: from v2.1.227 a banner or log line alongside it makes the helper fail.

#!/bin/bash
# ~/bin/proxy-token.sh
op read "op://Engineering/ai-proxy/token"
{ "apiKeyHelper": "~/bin/proxy-token.sh" }

On Windows, reference something like powershell -NoProfile -File C:\\tools\\proxy-token.ps1, escaping backslashes in JSON. Output is cached for five minutes; change that with CLAUDE_CODE_API_KEY_HELPER_TTL_MS (for example 900000 for 15 minutes). The value goes out in both Authorization and x-api-key. The settings reference entry for apiKeyHelper lists the other triggers for a re-run.

Silencing traffic outside the gateway

Version checks, telemetry, release notes and similar requests go to Anthropic and services like GitHub, not through the gateway. On an egress-locked network they show up as blocked connections. Claude Code only attaches a credential to telemetry or usage-metrics requests bound for the host that credential belongs to: with ANTHROPIC_BASE_URL set, telemetry goes to Anthropic without your gateway key, and with a gateway credential active, usage metrics are not reported to the Console analytics dashboard. (Before v2.1.246 the gateway credential could be attached to those Anthropic-bound requests.)

To switch it all off, set CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 next to the gateway variables. Be aware that it:

  • disables auto-updates, so you need another update route;
  • skips the fast mode availability check, so /fast reports unavailable unless a previous check already enabled it;
  • does not stop gateway model discovery (before v2.1.257 it froze the cached list);
  • does not stop the WebFetch domain safety check to api.anthropic.com; disable that separately with skipWebFetchPreflight: true.

Data usage lists each telemetry stream and its switch.

Gateways that speak a cloud provider's format

Use these only if your gateway team named Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry or Claude Platform on AWS. If the curl test returned JSON, you do not need them. Bedrock and Agent Platform routes accept those providers' native formats, and Claude Code trims the beta headers and fields it sends to what that provider accepts; Foundry and Claude Platform on AWS routes take the Anthropic Messages format.

ProviderVariables to set
Amazon BedrockCLAUDE_CODE_USE_BEDROCK=1, ANTHROPIC_BEDROCK_BASE_URL, CLAUDE_CODE_SKIP_BEDROCK_AUTH=1
Google Cloud's Agent PlatformCLAUDE_CODE_USE_VERTEX=1, ANTHROPIC_VERTEX_BASE_URL, ANTHROPIC_VERTEX_PROJECT_ID, CLOUD_ML_REGION, CLAUDE_CODE_SKIP_VERTEX_AUTH=1
Microsoft FoundryCLAUDE_CODE_USE_FOUNDRY=1, ANTHROPIC_FOUNDRY_BASE_URL, plus ANTHROPIC_FOUNDRY_API_KEY or ANTHROPIC_FOUNDRY_AUTH_TOKEN
Claude Platform on AWSCLAUDE_CODE_USE_ANTHROPIC_AWS=1, ANTHROPIC_AWS_BASE_URL, ANTHROPIC_AWS_WORKSPACE_ID, CLAUDE_CODE_SKIP_ANTHROPIC_AWS_AUTH=1

Notes per provider:

  • Skip-auth variables stop Claude Code signing requests with cloud credentials, since the gateway holds those. If the gateway also wants its own token on the Bedrock, Agent Platform or Claude Platform on AWS routes, add ANTHROPIC_AUTH_TOKEN (sent as bearer) or use ANTHROPIC_CUSTOM_HEADERS for another scheme. Keep the skip-auth variable set: without it, Claude Code strips any Authorization header those would add.
  • Bedrock: leave AWS_BEARER_TOKEN_BEDROCK unset. If set, it is sent as Authorization in place of your gateway token even with skip-auth on.
  • Agent Platform: the project ID and region go into each request path. Per-model region overrides (VERTEX_REGION_CLAUDE_*), version pins (ANTHROPIC_DEFAULT_OPUS_MODEL, ANTHROPIC_DEFAULT_SONNET_MODEL, ANTHROPIC_DEFAULT_HAIKU_MODEL) and capability declarations such as ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES work as described in Google Vertex AI and Model configuration.
  • Foundry: ANTHROPIC_FOUNDRY_API_KEY travels as x-api-key; ANTHROPIC_FOUNDRY_AUTH_TOKEN travels as bearer and wins if both are set (v2.1.203+). For a gateway that injects its own Authorization, set CLAUDE_CODE_SKIP_FOUNDRY_AUTH=1 and leave both unset.
  • Claude Platform on AWS: the workspace ID comes from your Claude Platform on AWS set-up.

Confirm with /status. A Bedrock route, for instance, shows API provider: Amazon Bedrock, a Bedrock base URL row and AWS auth skipped. If the base URL row is missing, the variable never reached the session.

Troubleshooting

SymptomLikely causeWhat to do
Startup warns about two credential sources and says auth may not work as expectedA gateway credential and a saved login are both present/logout to keep the gateway credential, or unset the variable
401 about an invalid tokenWrong credential, or right credential in the wrong headerRe-check the variable table; get a new key if revoked
Your apiKeyHelper script is failingThe helper printed nothing usableRun it by hand; re-authenticate to your vault. See Errors
Connection refused or Can't reach the API server, often after a pause for retriesWrong URL, or VPN or firewall blocking the pathRun the curl test, then check the address with the gateway team
API returned an empty or malformed response (HTTP 200)Something returned HTML (an error or login page) instead of an API responseFind the route in front of the gateway that is answering
400 mentioning context_management or Extra inputs are not permittedUpstream rejects fields Claude Code sendsSet CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1; for betas it does not cover, use the matching CLAUDE_CODE_USE_* provider variable
400 mentioning thinking or adaptiveUpstream model build lacks adaptive reasoning (requested for Claude 4.6+)Upgrade the upstream; on Opus 4.6 and Sonnet 4.6, CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1 also works
400 with a context limit in the gateway's own wordsGateway enforces a smaller window and rewrites the error, so auto-compact does not trigger/compact to recover; set CLAUDE_CODE_AUTO_COMPACT_WINDOW (clamped to at least 100,000) and lower CLAUDE_CODE_MAX_OUTPUT_TOKENS
Every request 400s over a tool schema pattern on v2.1.265 to v2.1.267Artifact tool schema uses \p{...} classes the gateway's regex engine rejectsUpdate to v2.1.268+, or turn artifacts off
Every request 400s over an unknown tool type such as advisor_20260301 on v2.1.275An advisor declaration was sent even with the advisor offUpdate to v2.1.276+, or set CLAUDE_CODE_DISABLE_ADVISOR_TOOL=1
Gateway models missing from /modelNames not built in, or a replacing modelPicker lineupEnable discovery, or add the models to the lineup
/fast says unavailable due to network issuesThe check goes straight to api.anthropic.com, or Anthropic rejected a gateway keyAllowlist the host or use the skip variables in Fast mode
/fast says disabled by your organisation with ANTHROPIC_AUTH_TOKENThe check needs a claude.ai login or Anthropic keySet CLAUDE_CODE_SKIP_FAST_MODE_ORG_CHECK=1
Asked to log in although curl worksNo credential readable before first-run setup; project env blocks apply only after the trust promptPut ANTHROPIC_AUTH_TOKEN in a shell export, ~/.claude/settings.json or managed settings
ANTHROPIC_API_KEY silently ignoredIt was declined at the one-time approvalTurn on Use custom API key in /config
This machine's managed settings require a first-party loginManaged settings set forceLoginMethod, forceLoginOrgUUID or forceLoginGatewayUrl, which cannot coexist with gateway credentialsAdmin removes those keys, or you drop the gateway credential
403 HTML page and nothing in gateway logsA WAF blocked the body (prompts contain XML-like tags and code)Exempt /v1/messages from body inspection, for example AWS WAF's CrossSiteScripting_Body rule
TLS errors though curl worksClaude Code's runtime does not trust your inspection proxy's CASet NODE_EXTRA_CA_CERTS; see Network configuration

Repeated login prompts after removing the gateway set-up are usually a credential storage issue; see Authentication.