If your Claude code passes temperature, top_p or top_k, upgrading to API version 2026-10-21 turns every one of those calls into a 400. That's the headline break. The rest of the migration (SDK majors, a new auth header, a Python type change) is smaller but easy to trip over in a gateway or a test suite.
Everything below comes from Anthropic's own pages, read on 2026-10-31: the API release notes, the versions page and the migration guide for 2026-10-21. The Python parts I ran myself, against a mock HTTP transport with a fake key, so no real API call was made. TypeScript, Go and the other SDKs are described from the guide and were not run.
What shipped on October 21
Per the release notes, Anthropic released API version 2026-10-21 plus new majors of its client SDKs and the ant CLI that send it by default:
| Package | New version |
|---|---|
Python (anthropic) | 2.0.0 |
TypeScript (@anthropic-ai/sdk) | 1.0.0 |
C# (Anthropic) | 13.0.0 |
| Go | 2.0.0 (module path ends in /v2) |
| Java | 3.0.0 |
| PHP | 1.0.0 |
| Ruby | 2.0.0 |
ant CLI | 2.0.0 |
The new versions are also licensed Apache 2.0 instead of MIT. No code change is needed for that, but a dependency-license scanner may flag it.
On Amazon Bedrock the new version only applies to Claude 4.7 and later models. If you call an older model there, Anthropic's guide says to stay on your current SDK version until you move that call to a newer model.
Decide: upgrade now, or pin and plan
The API version is not forced on you. The versions page says Anthropic preserves existing input and output parameters for any given version, so 2023-06-01 keeps working as documented. Upgrade now if you want the new SDK types and bug fixes, or if you want your code to match the current docs. Pin and plan if any of these is true:
- A request relies on a non-default
temperatureon a model that accepts one (Anthropic names Claude Sonnet 4.6 as an example). - A gateway you don't control reads
X-Api-Key. - You call older models on Bedrock.
Pinning is a real option, not a failure. Just write down why, so the next person doesn't "fix" it.
Messages API changes that return 400
These apply to POST /v1/messages, token counting, and each request inside a Message Batch created with 2026-10-21.
- Sampling parameters are removed.
temperature,top_portop_kreturn a 400 even at the default value. Without them a request samples with the defaults, including atemperatureof 1.0. - Documents in assistant messages. A
documentblock placed directly in anassistantmessage returns a 400. Send documents inusermessages. A document nested inside another block, such as a web fetch result Claude returned, is still accepted. - Citations in user messages. A
textblock with a non-emptycitationsarray in ausermessage returns a 400, including inside asearch_resultblock. Citations on assistant text you send back are still accepted, and so is"citations": {"enabled": true}on documents and search results.
The first one is the dangerous one, because it's invisible in a diff. It tends to live in a shared helper, a config file or a default argument.
grep -rnE "temperature|top_p|top_k" src/ --include=*.py --include=*.ts
Search for it, then decide for each hit whether the value was doing real work. On models that already accept only default sampling values (Claude 4.7 and later, per the guide) removing the parameter changes nothing about the output.
What I saw when I ran Python SDK 2.0.0
I installed anthropic==2.0.0 in a fresh virtualenv and ran a short script against a mock transport (the script is mine, written for this post; it builds the real request object and returns a canned reply). This is the real output:
anthropic 2.0.0
temperature in create() signature: False
top_p in create() signature: False
top_k in create() signature: False
max_tokens in create() signature: True
output_config in create() signature: True
thinking in create() signature: True
anthropic-version header: 2026-10-21
authorization header present: True
x-api-key header present: False
body keys: ['max_tokens', 'messages', 'model']
temperature=0.2: TypeError Messages.create() got an unexpected keyword argument 'temperature'
MessageParam(...): TypeError
api_key + auth_token: ValueError Pass at most one of `api_key=`, `auth_token=`, `credentials=`, `config=`, or `profile=`. Received `api_key=`, `auth_token=`.
Four things to read out of that:
- The SDK sends
anthropic-version: 2026-10-21on its own. - The key goes out as
Authorization, andx-api-keyis not sent. temperatureis gone from the method signature, so you get aTypeErrorin Python before any network call. That's friendlier than a 400, but it also means code that passestemperature=through**kwargsfails at the call site.- Constructing a client with two credentials raises
ValueError.
One side detail: the v2 HTTP layer is httpx2 (pip pulled it in as a dependency). If you wrote a custom http_client= with the httpx package, check that it still type-matches. Anthropic's own example for putting the key back in X-Api-Key imports httpx2.
SDK changes that are not about the API version
Anthropic's guide lists breaking changes in the SDKs that you'd hit even if you never cared about the API version. The ones most readers will meet:
MessageParam is a union. Each role has its own type: UserMessageParam, AssistantMessageParam, SystemMessageParam, with matching Beta versions. Dict literals like {"role": "user", "content": "Hello"} need no change. In Python, calling MessageParam(...) now raises TypeError (I confirmed this above), so replace it:
# Before
message = MessageParam(role="user", content="Hello")
# After
message: MessageParam = {"role": "user", "content": "Hello"}
A helper that builds a dict whose role is a variable holding more than one role no longer type-checks. Build the dict one role at a time. In TypeScript an interface can't extend the union, so use a type alias:
// Before
interface StoredMessage extends Anthropic.MessageParam { id: string }
// After
type StoredMessage = Anthropic.MessageParam & { id: string };
API keys go out as Authorization: Bearer. If a proxy reads X-Api-Key, either change the proxy or set the header yourself. For Python the guide shows an auth function on the HTTP client that moves the key back; for TypeScript it's defaultHeaders: { "X-Api-Key": apiKey, Authorization: null }. ant can't send X-Api-Key at all, so a proxy in front of the CLI has to read Authorization.
A client holds one credential. Passing both an API key and an auth token used to send both. Now Python raises ValueError and TypeScript throws TypeError. If you relied on a gateway token plus an API key, Anthropic's guide says to pass the token as the auth token and set X-Api-Key as a default header, and have the gateway strip its Authorization before forwarding.
Client-side compaction is removed from the TypeScript and Ruby tool runner. The compactionControl option is gone. The replacement in the guide is server-side compaction with betas: ["compact-2026-01-12"] and a context_management edit of type compact_20260112; the trigger threshold must be at least 50,000 tokens.
Other one-liners:
- Text Completions is removed from the TypeScript, Go, Java and Ruby SDKs and the CLI. Use Messages.
- The non-beta Models methods no longer take
betas. Callclient.beta.modelsinstead. ant --api-keyand--auth-tokenflags are removed; useANTHROPIC_API_KEYor--api-key-stdin.- Go needs 1.25 or later, and the import path gains
/v2. go installwith the oldantpath keeps installing v1 with no warning, so add/v2.
Admin and Enterprise Analytics field renames
If you parse Admin API or Enterprise Analytics responses, the old names are gone under 2026-10-21:
| Endpoint | Old | New |
|---|---|---|
| RBAC groups | roles | role_ids |
| RBAC group members | group_id | rbac_group_id |
| RBAC roles | name | display_name |
| Rate limits | group_type | group.type |
| API keys | workspace_id | scope.workspace_id |
| Per-user usage and cost reports | actor.email | actor.email_address |
| Activity summaries | summaries | data |
The API key one has a trap. Before, a null workspace_id meant either the Default Workspace or an all-workspaces key. Now a key bound to the Default Workspace reports its real ID in scope.workspace_id, and an all-workspaces key has scope of {"type": "organization"} with no workspace_id. Code that treated null as "default" has to compare against the Default Workspace's real ID (the guide says to find it with List Workspaces and include_default=true).
Let Claude Code do the first pass
Claude Code 2.1.307 (October 21) added a /claude-api api-version command "to move Claude API code to API version 2026-10-21", according to the Claude Code changelog. I haven't run it. Treat its diff like any generated diff: read it, and still grep for sampling parameters yourself, because a model-written migration is exactly where a stray temperature in a config file gets missed. The older posts on migrating from Claude 3.5 and 4.5 to 4.6 and migrating prompts to new models cover the model side; this post is the transport side.
The checklist
Copy this into your PR description.
- Decide: upgrade or pin
2023-06-01. Write the reason down. - List every place that sends
temperature,top_p,top_k(code, config, env, gateway defaults). Remove them. Note any that relied on a non-default value. - Search for
documentblocks in assistant messages andcitationson user text blocks. Move or remove. - Upgrade the package: Python
anthropic2.0.0, TypeScript@anthropic-ai/sdk1.0.0 (and the Bedrock/Vertex/Foundry packages to v1 in the same change, per the guide), Go/v2import paths, and so on. - Replace
MessageParam(...)constructor calls, subclasses and role-generic helpers. - Check every proxy, log filter and test stub for
X-Api-Key. Switch toAuthorizationor set the header explicitly. - Make sure no client gets two credentials.
- If you use the TypeScript or Ruby tool runner with compaction, move to the server-side form.
- If you read Admin or Analytics responses, apply the rename table.
- On Bedrock with pre-4.7 models, stay on the old SDK for those calls.
- Run your test suite, then a canary with real traffic. A 400 here is an
invalid_request_error, so alert on that class for a day. - Update your dependency-license record for Apache 2.0.
If the same PR also swaps models, read the model picker and the Sonnet 5.5 and Haiku 5.5 error reference, because the two sets of 400s overlap on sampling parameters. Keep them in separate commits so you can tell which change broke which call.
What I couldn't verify
- I didn't run the TypeScript, Go, Java, C#, PHP or Ruby SDKs. Their behaviour here is from Anthropic's migration guide.
- I didn't run
/claude-api api-versionor make any live API call. There is no API key in this environment. - The Claude Code changelog page is very long and the fetch tool read only the first part; I confirmed the 2.1.307 entry but not whether other entries mention the version helper.
- The guide says the bug-fix list for 2.1.307 is collapsed on the page; I didn't read it.



