Max Narditdata & ai systems
← Articles
7 mindev

Claude API 2026-10-21 and the new Anthropic SDKs: the key moves to Authorization: Bearer, and a gateway that reads X-Api-Key loses it

For a client that calls the API directly, the header move needs no change. A gateway has to read both shapes, because Claude Code and every pinned service keep sending the old one, and an SDK client now refuses to hold a gateway token and an upstream key at once.

Contents

On October 21 Anthropic released API version 2026-10-21 and new majors of all seven SDKs plus the ant CLI, each sending the new version by default. Most of the migration guide is type reshuffling. One line in it changes what crosses the network: the SDKs now send your API key as Authorization: Bearer instead of X-Api-Key.

For a client that calls the API directly, that line needs no change, since the API reads the key from either header. The break lands in the middle. A gateway, proxy or custom middleware that reads X-Api-Key stops finding the key, and a client that used to carry a gateway token plus an upstream key now refuses to be built. No flag brings the old behavior back. And the old shape doesn’t go away: Claude Code 2.1.307 still sends it, so a gateway gets both on the same day. I ran both SDK generations, and Claude Code, against a local listener that logged headers, with dummy keys and nothing forwarded, to see what a gateway receives.

What does the new Anthropic SDK send to a gateway?

A different credential header and a different version string. Those are the headers I logged, and the top-level body keys were the same across generations. This is what the listener recorded for the same messages.create call with api_key set:

anthropic 1.17.0   x-api-key: sk-ant-FAKE-key           anthropic-version: 2023-06-01
anthropic 2.1.0    authorization: Bearer sk-ant-FAKE-key anthropic-version: 2026-10-21
sdk (JS) 0.137.0   x-api-key: sk-ant-FAKE-key           anthropic-version: 2023-06-01
sdk (JS) 1.1.0     authorization: Bearer sk-ant-FAKE-key anthropic-version: 2026-10-21

There is no X-Api-Key at all on the new side. A gateway that authenticates its own users from that header sees a request with no credential. If it rejects such requests, you get a 401 on deploy day, which is the good case. The risky design is one that forwards a request anyway when its own credential is missing: then whatever per-user attribution hung on X-Api-Key can be lost, and the request leaves with whatever the client put in Authorization. That is a design risk to check in your gateway, not something I observed.

The listener is the same idea as the one in the Claude Code gateway walkthrough, with one change: instead of answering 503 it returns a stub message object, so the SDK parses a reply and exits cleanly. Point a client at it with base_url="http://127.0.0.1:8765" and a fake key and you can compare both majors in a minute.

Why does an Anthropic SDK 2.x client refuse a gateway token and an API key together?

Because the key and the auth token now share a header, so a client holds one credential. In 1.x, a client built with both sent both, X-Api-Key for the key and Authorization for the token, and that pairing was a common gateway setup: the token authenticates you to the gateway, the key goes upstream. In 2.1.0 the same constructor fails before any request:

ValueError: Pass at most one of `api_key=`, `auth_token=`, `credentials=`, `config=`, or `profile=`. Received `api_key=`, `auth_token=`.

TypeScript 1.1.0 throws a TypeError with the same wording for apiKey plus authToken. The guide lists the equivalents: ArgumentException in C#, IllegalStateException at build() in Java, InvalidArgumentException in PHP, ArgumentError in Ruby. Go is the odd one out: NewClient returns no error, so every request that client makes fails instead.

The documented way to keep the pair is to pass the gateway token as the credential and add the key as a plain header. On 2.1.0 this produced both headers on the wire, token in Authorization and key in X-Api-Key:

python
client = anthropic.Anthropic(
    auth_token=gateway_token,
    default_headers={"X-Api-Key": upstream_key},
    base_url=gateway_url,
)

The other half is the gateway’s job. The guide is explicit that the gateway should remove its Authorization header before forwarding, because “the Claude API expects one credential per request.” A gateway that passes everything through now sends two.

Environment variables have a quieter version of this. Per the guide, with nothing passed in code and both ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN set, the new clients use the key and log a warning once. If your deployment relied on both reaching the gateway, one of them stops.

How do you make an Anthropic SDK 2.x client send X-Api-Key again?

Per language, with no global switch. In Python the guide’s fix is an auth hook on the HTTP client that runs on every request, retries included. On 2.1.0 it moved the key back: the listener saw x-api-key and no authorization. The import is httpx2, which the SDK already used in 1.17.0, not httpx.

python
import httpx2
from anthropic import Anthropic, DefaultHttpxClient
 
 
def send_x_api_key(request: httpx2.Request) -> httpx2.Request:
    if request.headers.get("Authorization") == f"Bearer {api_key}":
        del request.headers["Authorization"]
        request.headers["X-Api-Key"] = api_key
    return request
 
 
client = Anthropic(
    api_key=api_key,
    base_url=gateway_url,
    http_client=DefaultHttpxClient(auth=send_x_api_key),
)

In TypeScript it is two default headers, and Authorization: null is what keeps the key from going out twice. Version 1.1.0 sent only x-api-key with this:

typescript
const client = new Anthropic({
  apiKey,
  baseURL: gatewayUrl,
  defaultHeaders: { "X-Api-Key": apiKey, Authorization: null },
});

Go uses option.WithHeader("X-Api-Key", apiKey) plus option.WithHeaderDel("Authorization"), Java putHeader instead of apiKey, PHP and Ruby a middleware. Two details in the guide are easy to miss. In PHP, don’t use extraHeaders for this: any request with extraHeaders of its own replaces the client’s, and every beta endpoint has them. And the ant CLI has no way to add a header, so a gateway in front of ant has to learn Authorization; there is no client-side fix.

Per-request header code changes meaning too, in both directions. Per the guide, in Python, TypeScript, Go and PHP a per-request X-Api-Key no longer replaces the client’s key; both go out, so the override belongs in Authorization. And code that deleted X-Api-Key to send only an auth token should be deleted, not renamed: removing Authorization instead would remove the token.

Does Claude Code also move to Authorization: Bearer?

Not in 2.1.307. Claude Code is not on the SDK list, and 2.1.307, the release that added /claude-api api-version to migrate your code to 2026-10-21, still sent the old shape when I pointed it at the listener with ANTHROPIC_API_KEY set:

POST /v1/messages?beta=true
user-agent: claude-cli/2.1.307 (external, sdk-cli)
anthropic-version: 2023-06-01
x-api-key: sk-ant-FAKE-key

So for an API key the mapping in the gateway post still holds: ANTHROPIC_API_KEY goes out as x-api-key. (I didn’t rerun ANTHROPIC_AUTH_TOKEN; the gateway docs say it goes out as Authorization: Bearer.) Some SDK clients don’t change at all: per the guide, the Foundry clients still send x-api-key, and the Bedrock Mantle clients already sent a bearer token. A gateway that serves developers in Claude Code and services on the new SDKs gets both shapes on the same day, and will for as long as anything pins Python below 2.0 or TypeScript below 1.0.

What does Claude API 2026-10-21 do to temperature on Sonnet 4.6?

It rejects it. Under 2026-10-21, a Messages or Batch request carrying temperature, top_p or top_k returns 400 even at the default value. On Claude 4.7 and later the sampling itself doesn’t change, since those models already accept only the defaults, as the Opus 5.5 migration notes covered, but a request that spells out a default still has to drop it. On models that still take other values, such as Sonnet 4.6, a low temperature for classification or grading is gone and, per the guide, nothing replaces it.

The SDK side moved earlier than you might expect. In my runs temperature was already not a keyword argument of messages.create in Python 1.17.0, and 2.1.0 is the same: both raise TypeError on it. Code that still sends it does so through extra_body, which both versions passed through untouched. On 2.1.0 the default version makes that a 400 at the server.

The guide’s choice is to drop the parameter or keep that request on 2023-06-01. On 2.1.0 you can keep it per request without pinning the whole SDK; the listener saw anthropic-version: 2023-06-01 and temperature in the body:

python
client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=256,
    messages=messages,
    extra_headers={"anthropic-version": "2023-06-01"},
    extra_body={"temperature": 0.0},
)

That pin only survives a gateway that forwards anthropic-version unchanged, as the gateway compatibility guide asks. A gateway that rebuilds requests with its own SDK, or stamps one version on everything upstream, decides this for every client behind it, and the day it upgrades, an old client’s temperature: 0 becomes a 400. The pin also undoes nothing on the client side: the credential header is an SDK change, not an API version change.

I would treat the pin as a bridge with a date on it. My read: if the score or label really depends on temperature 0, measure the same sample at 1.0 now, while you can still compare both, and let the numbers decide.

What else breaks in the Anthropic SDK upgrade?

A few things that fail later, without an error, or only on some traffic:

  • Go’s import path. The SDK is now github.com/anthropics/anthropic-sdk-go/v2, so every import changes, and code left on the old path stays on v1. The ant CLI is the sharper case: its module path also ends in /v2, and the old go install path keeps installing the latest v1 with no error or warning. A build script that “upgraded” can still be on the old wire.
  • Conversation history. Under 2026-10-21, per the guide, a document block placed directly in an assistant message and non-empty citations on text blocks in a user message both return 400, in token counting and batches too. A gateway or app that rebuilds history by moving blocks between roles is where this shows up.
  • TypeScript platform packages. @anthropic-ai/bedrock-sdk, vertex-sdk and the other platform packages need the matching core major, or the package manager installs a second copy of @anthropic-ai/sdk.
  • Bedrock before Claude 4.7. On Amazon Bedrock, 2026-10-21 works only for Claude 4.7 and later. Calls to Opus 4.6 or older there stay on the old SDK or keep sending the old version.

What should a gateway operator fix first for the new Anthropic SDKs?

The gateway, not the clients. Pinning clients below the new majors buys time only for code you control, and you rarely control all of it: another team’s dependency bot opens the upgrade PR, or a new service starts on the current SDK. Claude Code, meanwhile, keeps sending x-api-key. The gateway is the one place that sees all of these clients, so it is the place to accept both shapes.

What “accept both” means depends on whose key goes upstream. If the gateway holds the upstream credential, read the caller’s gateway credential from X-Api-Key or, failing that, from Authorization after Bearer , check it, strip both headers and set your own before forwarding. If callers bring their own upstream key next to a gateway token, the documented split is token in Authorization, key in X-Api-Key: authenticate the token, remove Authorization, forward the key. Either way, decide what happens when both headers arrive and they disagree, rather than letting header order decide. Forward anthropic-version as it came, and log which header each request used, so you can see when the old shape fades out and catch a forward-anyway path before it costs you the attribution. Then point one client of each generation at a header-logging listener before the first service upgrades for you.

01 / Discussion

No comment section here — all discussions happen on X.

Max Nardit@mnardit

02 / More articles