ANTHROPIC_BASE_URL explained: run a coding agent through a custom endpoint

Two environment variables move a terminal coding agent onto a gateway: the base URL and a bearer token. What to set, how to check it, and what stops the first call.

GTokens teamUpdated

The short answer

Set ANTHROPIC_BASE_URL=https://api.gtokens.io and ANTHROPIC_AUTH_TOKEN=sk-sl-…, leave ANTHROPIC_API_KEY empty, and name models by their catalogue identifiers, such as anthropic/claude-sonnet-5-5. The agent, its prompts and its tools stay as they are.

  • The base URL is the root of the gateway, without /v1 — the client appends /v1/messages itself.
  • The key travels as a bearer token. The x-api-key header is not read on any route, so a key placed in ANTHROPIC_API_KEY arrives in a header the gateway ignores.
  • Model names are catalogue identifiers in the form vendor/model. A built-in name such as claude-sonnet-4-6 is not in the catalogue and comes back 404.
  • One request with curl tells you whether the URL and the key are right before the agent starts.

What the two variables do

Terminal coding agents such as Claude Code, and runtimes built on the same client, read two environment variables to decide where requests go and how they are signed. Both are read at start-up, so set them before you launch the agent.

The variables and what they send
VariableValueWhat the client does with it
ANTHROPIC_BASE_URLhttps://api.gtokens.ioSends every request to this host and appends the route path itself.
ANTHROPIC_AUTH_TOKENsk-sl-…Sends the key as Authorization: Bearer — the header the gateway reads.
ANTHROPIC_API_KEYemptyWould send x-api-key, which the gateway does not read.

Scroll the table sideways for the last column.

shell
export ANTHROPIC_BASE_URL=https://api.gtokens.io
export ANTHROPIC_AUTH_TOKEN=sk-sl-your-key

# Empty on purpose: this variable sends a header the gateway does not read.
export ANTHROPIC_API_KEY=
PowerShell
$env:ANTHROPIC_BASE_URL = "https://api.gtokens.io"
$env:ANTHROPIC_AUTH_TOKEN = "sk-sl-your-key"
Remove-Item Env:ANTHROPIC_API_KEY -ErrorAction SilentlyContinue

The third line is not decoration. With two credentials present the agent warns about an auth conflict at start-up, and an old key left in ANTHROPIC_API_KEY is the most common reason the first call comes back 401.

Set it once for every session

Shell exports last as long as the terminal. To make the setting stick for every session, including ones started from an editor, put the same values in the env block of the user settings file, ~/.claude/settings.json (on Windows, %USERPROFILE%\.claude\settings.json):

~/.claude/settings.json
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.gtokens.io",
    "ANTHROPIC_AUTH_TOKEN": "sk-sl-your-key",
    "ANTHROPIC_MODEL": "anthropic/claude-sonnet-5-5",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "anthropic/claude-opus-5-5",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "anthropic/claude-sonnet-5-5",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "anthropic/claude-haiku-5-5"
  }
}

When a shell export and the settings file disagree, the settings file wins. Keep the key out of a project’s .claude/settings.json: that file is committed with the repository and travels to everyone who clones it.

Name the models the agent will ask for

The gateway answers to catalogue identifiers only. There are no aliases and no substitution: the model you name is the model that answers, and a name it does not know is refused with 404 rather than mapped to something close.

An agent asks for more than one model during a session: the main one for the work, others when you switch, and a small one for background tasks such as naming the session. Pin all of them, and nothing in a session asks for a name the catalogue does not carry:

shell
export ANTHROPIC_MODEL=anthropic/claude-sonnet-5-5
export ANTHROPIC_DEFAULT_OPUS_MODEL=anthropic/claude-opus-5-5
export ANTHROPIC_DEFAULT_SONNET_MODEL=anthropic/claude-sonnet-5-5
export ANTHROPIC_DEFAULT_HAIKU_MODEL=anthropic/claude-haiku-5-5

The text models this post uses are listed with their identifiers at the end of it; the whole list is on the models page and from GET /api/v1/models.

Check the connection before you rely on it

Send one request with the same two values before you start the agent. It takes a second, costs a fraction of a cent, and separates a wrong URL or key from everything else:

shell
curl -sS "$ANTHROPIC_BASE_URL/v1/messages" \
  -H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-haiku-5-5",
    "max_tokens": 1,
    "messages": [{"role": "user", "content": "ping"}]
  }'

A JSON reply with "type": "message" means the URL, the key and the model name are all right. Then start the agent from the same terminal and run /status: the base URL line should show the gateway address, and the credential line should name ANTHROPIC_AUTH_TOKEN. If the base URL line is missing, the variable did not reach the session.

When the first call fails

Errors on this route come back in the envelope the client library expects, so the agent shows the status and the message as they are. The ones that stop a first call:

First-call errors and their fixes
StatusWhat it meansWhat to do
401The key is missing, unknown or revoked — or it went out in the header the gateway does not read.Put the key in ANTHROPIC_AUTH_TOKEN, empty ANTHROPIC_API_KEY, and check in the account area that the key is not revoked.
402The balance cannot cover the request, or a spending ceiling was reached. Nothing is charged.Top up the balance. If a ceiling was reached instead, the request goes through once the ceiling’s period resets or the ceiling is raised.
404No model in the catalogue goes by that identifier.Pin the model variables to catalogue identifiers.
400The model is listed but not served yet, or the model itself refused the request — then the text is its own.Pick a served model, or read the message: it names what to change.
503The model is temporarily unavailable. Retry-After is always set.Repeat the same request after Retry-After; the agent retries with backoff on its own.

Scroll the table sideways for the fix.

A login screen instead of a session

If the agent opens its login screen even though the curl test works, it has no credential at start-up: a reachable base URL is not one. Set ANTHROPIC_AUTH_TOKEN as a shell export or in the user settings file — a project settings file is read only after the first-run setup.

The same setup in the Agent SDK

The Agent SDK starts the same agent under the hood and hands it its environment, so everything above applies unchanged. One difference bites: in TypeScript, options.env replaces the environment of the agent process instead of adding to it, so spread process.env into it first. In Python, env is merged on top of the inherited environment.

agent.ts
import { query } from '@anthropic-ai/claude-agent-sdk'

for await (const message of query({
  prompt: 'Summarise what this repository does, in five lines.',
  options: {
    model: 'anthropic/claude-sonnet-5-5',
    // env REPLACES the environment of the agent process: spread the parent
    // environment first, or PATH and everything else are gone.
    env: {
      ...process.env,
      ANTHROPIC_BASE_URL: 'https://api.gtokens.io',
      ANTHROPIC_AUTH_TOKEN: process.env.GTOKENS_KEY,
    },
  },
})) {
  if (message.type === 'assistant') console.log(message.message.content)
}
agent.py
import os
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions

# In Python, env is merged on top of the inherited environment.
options = ClaudeAgentOptions(
    model="anthropic/claude-sonnet-5-5",
    env={
        "ANTHROPIC_BASE_URL": "https://api.gtokens.io",
        "ANTHROPIC_AUTH_TOKEN": os.environ["GTOKENS_KEY"],
    },
)

async def main():
    async for message in query(
        prompt="Summarise what this repository does, in five lines.",
        options=options,
    ):
        print(message)

anyio.run(main)

What an agent session costs

Every request is billed per token at the rates published for its model, from a prepaid balance, and a refused request costs nothing. An agent session resends its context on every turn, so much of what it reads can come from the prompt cache — and the cache-read rate is the lowest of the four counters. The current rates are on each model’s page in the catalogue.

The Messages route answers in the shape the client library expects, and that shape has no field for money, so the agent does not print a price. The request log in your account shows what each call cost, and GET /api/v1/credits returns the running total.

More in Guides

All in Guides →