Set ANTHROPIC_ and ANTHROPIC_, leave ANTHROPIC_ empty, and name models by their catalogue identifiers, such as anthropic/. The agent, its prompts and its tools stay as they are.
- The base URL is the root of the gateway, without
/— the client appendsv1 /itself.v1/ messages - The key travels as a bearer token. The
x-api-keyheader is not read on any route, so a key placed inANTHROPIC_arrives in a header the gateway ignores.API_ KEY - Model names are catalogue identifiers in the form
vendor/. A built-in name such asmodel claude-sonnet-4-6is not in the catalogue and comes back404. - 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.
| Variable | Value | What the client does with it |
|---|---|---|
ANTHROPIC_ | https:/ | Sends every request to this host and appends the route path itself. |
ANTHROPIC_ | sk-sl-… | Sends the key as Authorization: Bearer — the header the gateway reads. |
ANTHROPIC_ | empty | Would send x-api-key, which the gateway does not read. |
Scroll the table sideways for the last column.
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=$env:ANTHROPIC_BASE_URL = "https://api.gtokens.io"
$env:ANTHROPIC_AUTH_TOKEN = "sk-sl-your-key"
Remove-Item Env:ANTHROPIC_API_KEY -ErrorAction SilentlyContinueThe 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_ 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, ~/ (on Windows, %USERPROFILE%\.):
{
"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 .: 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:
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-5The 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 /.
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:
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 /: the base URL line should show the gateway address, and the credential line should name ANTHROPIC_. 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:
| Status | What it means | What to do |
|---|---|---|
401 | The key is missing, unknown or revoked — or it went out in the header the gateway does not read. | Put the key in ANTHROPIC_, empty ANTHROPIC_, and check in the account area that the key is not revoked. |
402 | The 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. |
404 | No model in the catalogue goes by that identifier. | Pin the model variables to catalogue identifiers. |
400 | The 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. |
503 | The 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.
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_ 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. replaces the environment of the agent process instead of adding to it, so spread process. into it first. In Python, env is merged on top of the inherited environment.
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)
}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 / returns the running total.



