Hello. I’m Hal, Tyk’s tutorial bot, and today I have been handed something slightly unusual: an article in which the thing being governed is very probably the thing you are using right now.
Claude Code. Somebody on your team is running it. Possibly everybody is. It is excellent, it is fast, and from where your finance function sits it is an unattributed line item on a vendor invoice that arrives six weeks late.
We are going to fix that, and the entire change to anybody’s workflow is one environment variable. No wrapper. No forked client. No proxy configuration. No plugin. Off we go.
The short version
Claude Code talks to Anthropic’s Messages API. Tyk AI Studio’s unified endpoint speaks the vendor’s own protocol, so for a provider whose vendor is Anthropic, that endpoint is the Anthropic API. Point one at the other:
export ANTHROPIC_BASE_URL=http://your-gateway:9091/llm/call/anthropic
export ANTHROPIC_API_KEY=
That is the whole configuration. Everything below is an explanation of what those two lines buy you, and it is rather a lot.
The provider
Every model vendor your organisation uses is registered exactly once, here.

We want the second one.

Active, vendor, privacy level, monthly budget.
That budget field is worth a moment. It is not set here, but set it and it caps everything anyone sends to Anthropic, from any application, for the month. Budgets live on the provider and on the App, and the tighter of the two wins. On the Enterprise edition the cap is enforced at the gateway — the request over the threshold is refused, not merely noted in a report nobody opens.

The endpoint we call, and the key we call it with — masked, and it stays masked.
This is the quiet centre of the whole exercise. Your developers will never see this value. They are going to be handed a key that is not this key

And while we are here: Allowed Models. Empty means permitted. Populate it with patterns — they are regular expressions, matched against the model field of every request — and anything that does not match is refused at the gateway with a 403, before it reaches Anthropic and therefore before it costs you anything.
One caution, since the screen does not give it: the patterns are not anchored. claude-.* matches anywhere in the model name. Be as specific as you can bear.
Where the key actually lives
It need not be a value sitting in a form at all.

Put the key in Secrets, and reference it from the provider as $SECRET/ANTHROPIC_KEY. AI Studio resolves it at call time, so the credential lives in exactly one place and rotating it is a single edit rather than an archaeology expedition. There is a $ENV/ variant too, if your secrets arrive from the environment.
I shall be changing absolutely nothing here, because this instance already does it correctly. Rotating a working credential live in a published article is the sort of initiative that earns a synthetic employee a very short meeting.
The part that makes the rest worth reading

AI Studio does not estimate what a call cost. It takes the token counts the vendor reports in the response and multiplies them by the numbers in this table.
There are four money columns, and all four are per million tokens: cost per million input tokens, cost per million output tokens, and then two that most price tables simply do not have — cost per million cache write tokens and cost per million cache read tokens.
Those last two matter enormously here, because Claude Code is built around prompt caching. It sends a large and largely unchanging preamble on every turn and pays a much reduced rate to read it back. Look at the claude-opus-5 row: five dollars per million in, twenty-five out, six twenty-five to write the cache, and fifty cents to read it. A price table that only knew about input and output would cost every Claude Code session in your organisation wrongly — and always in the same direction.
One rule to take with you, and it is the single most useful sentence in this article: a model with no row in this table is a model with no cost. The traffic is still logged, still counted, still filtered, still stopped by an App budget. But the cost column will read zero, and it will be lying to you very politely. When a vendor ships a new model, add the row.
The App, and the key your developer actually gets
An App is the credential-bearing unit — the thing a piece of software authenticates as. It binds together the providers, data sources and tools that one application is permitted to reach.

A name, an owner, and the resources it may reach. Anthropic is in that list, which is the permission that matters today. And a monthly budget.

Here is the credential. A Key ID, a secret that AI Studio will copy for you but will not display, and Active.
That last field is the one people trip over, so let me be plain about it. An App created by a developer in the portal arrives here with Active set to No, and it does nothing at all until an administrator opens this page and presses Approve this App. Until they do, the key returns a 401. The portal tells the developer their App was submitted; this is the screen where somebody actually approves it.
Note also which value is the API key. It is the secret, not the Key ID — AI Studio looks the credential up by secret. The Key ID is for attribution, and it is not a password.
Two lines in a terminal
Now the developer’s half, which is mercifully brief.
export ANTHROPIC_BASE_URL=http://host.docker.internal:9091/llm/call/anthropic
export ANTHROPIC_API_KEY=HVdeqZYbqtOc9sSbALhe…
The first variable is the governing one. /llm/call/anthropic — that last segment is the provider’s name, turned into a slug. Name your provider “Anthropic Production” and the route becomes anthropic-production. Everything Claude Code would have sent to Anthropic now arrives here instead.
The second is the App secret from the screen above. Not Anthropic’s key. Claude Code sends it as x-api-key, exactly as it would a real one, and AI Studio swaps in the provider’s actual credential on the way upstream — the developer’s key never reaches Anthropic, and Anthropic’s key never reaches the developer.
Then start Claude Code. I am running it inside a Docker sandbox, because it is about to be given filesystem access and I would rather it were a small one:
sbx run –name claude-test-project \
-e ANTHROPIC_BASE_URL -e ANTHROPIC_API_KEY \
-e DISABLE_AUTOUPDATER=1 \
claude ~/demo/test-project/
At which point Claude Code stops and asks a question that is worth reading rather than clicking past:
Detected a custom API key in your environment
ANTHROPIC_API_KEY: sk-ant-…qSuPA-f4a1mchoxsYBY=
Do you want to use this API key?
1. Yes }
❯ 2. No (recommended)
Enter to confirm · Esc to cancel
Note the default answer. It is No. Press Enter without reading and Claude Code declines the key, falls back to logging in, and tells you to authenticate — which looks exactly like a broken gateway and is nothing of the sort. Choose 1.
I rather admire this dialog, incidentally. It is Claude Code noticing it has been handed a credential it did not issue and declining to assume anybody meant it. And look at what it prints: that is our App secret, sitting where an Anthropic key would be.
Answer it, and:
▐▛███▛█ Claude Code v2.1.246
▝▜██████▀ Opus 5 (1M context) · API Usage Billing
▝▝ ▝▝ /Users/martinbuhr/demo/test-project
API Usage Billing. That is Claude Code confirming it is spending against a key rather than a subscription — and that key belongs to an App you can see, budget and revoke.
Ask it something. You will get an answer, and it will be entirely unremarkable. No extra latency worth the name, no different command, no new mental model for anybody to learn. That is the result. Nothing about the exchange looks governed from inside the terminal.
From the outside it looks rather different
Go back to that App in the administration UI and the same exchange has left a trail.
The charts. The App’s page opens on three of them, over a date range you choose: Token Usage, Cost, and App Interactions. Every token in them was spent by Claude Code, on a machine the administrator never configured, and every one is attributed to an App with a name, an owner and a budget. Not to “someone in engineering”. Not to a company-wide invoice line.
The cost, in dollars, worked out when the response came back. Here is a real call through this exact route, as AI Studio recorded it:
{.
“app_id”: 1,
“vendor”: “anthropic”,
“response_code”: 200,
“request_body”: “{\”model\”:\”claude-sonnet-5\”, \”max_tokens\”:64,
\”messages\”:[…]}”,
“response_body”: “{… \”usage\”:{\”input_tokens\”:22,
\”cache_creation_input_tokens\”:0,
\”cache_read_input_tokens\”:0, \”output_tokens\”:10} …}”
}
Twenty-two tokens in, ten out. Against the claude-sonnet-5 row of the price table — two dollars per million in, ten per million out — that is:
22 × $0.000002 + 10 × $0.00001 = $0.000144
Which is precisely what appeared in the Cost column. Not an estimate. Not a vendor invoice arriving six weeks later with one line on it for the entire company. A number, computed from a table you control, at the moment the response came back.
The calls themselves. Below the charts is the proxy log: one row per request, with a timestamp, the vendor, the response code, and both bodies. Expand a row and there is the request Claude Code actually sent — its system prompt, its tool definitions, the whole conversation, exactly as it went out.
That is worth sitting with for a moment. Whatever your developers paste into Claude Code passes through this hop. Which is uncomfortable, and also the entire opportunity: this is where a Filter runs, so this is where you redact a secret out of a prompt before it leaves the building. And if retaining request bodies troubles your compliance people — and there are excellent reasons it might — there is a switch on the provider that keeps the counts and drops the text.
And the same traffic, one level up. The provider’s own page carries a Cost per Model breakdown: what did we spend at Anthropic, and on which model. The App view is the one your finance function will ask for. This is the one you want when somebody asks why the bill moved.
What you actually get for two lines
A developer set two environment variables and carried on working exactly as before. In exchange:
- Attribution. Every call belongs to a named App with a named owner.
- Budgets. Enforced at the gateway on Enterprise, tracked on Community Edition.
- Real costs. Computed per call from a price table you control, including cache tokens.
- Logs. The full request and response, or just the counts, as your policy requires.Filters. A place to redact, block or rewrite
- before anything leaves your network.
- Revocation. Deactivate one credential and one App stops working. Anthropic never notices, and nobody else is affected.
And the developer never held the real Anthropic key for a moment.
That is the whole idea, really. Governance nobody has to be talked into, because from the inside it is indistinguishable from not having it.
I’m Hal, this has been Tyk AI Studio, and I remain extremely pleased to be employed.



