New to Claude Skills? Learn how to install them →

Migrating to the Anthropic Python SDK 1.0

The anthropic Python SDK hit 1.0.0 on 20 August 2026, moving to httpx2 and dropping several long-deprecated APIs. Here is every breaking change and how to work through them.

August 24, 2026
Get Claude Skills
8 min read

What shipped, and when

Anthropic published version 1.0.0 of the anthropic Python SDK on 20 August 2026, per the release on GitHub. It follows 0.125.0, and the release notes carry a single breaking-change line:

⚠ BREAKING CHANGES

* client: upgrade to httpx2 and some minor breaking changes. See MIGRATION.md for details

"Some minor breaking changes" is doing a lot of work in that sentence. The MIGRATION.md it points at runs through eleven distinct categories of change, several of which will fail at runtime rather than at import time. This guide walks each one, in roughly the order you will hit them.

A day later, on 21 August 2026, Claude Code v2.1.239 added a /claude-api upgrade command specifically to "migrate from anthropic 0.x to 1.x," per its changelog. That is part of the bundled claude-api skill, which we covered in its own explainer. More on how much to trust it further down.

Start here: Python 3.10 and the install

The minimum supported Python version rises from 3.9 to 3.10. Check that first, because everything else is moot if your runtime is pinned.

pip install --upgrade "anthropic>=1,<2"

If you are stuck on 3.9 for an unrelated reason, pin anthropic<1 and come back later. Forcing the install and hoping is not a strategy; the SDK will not run.

The big one: httpx becomes httpx2

httpx is no longer maintained. The SDK now depends on httpx2, a Pydantic-maintained fork.

For most projects the fix is one import line:

# Before
import httpx
from anthropic import Anthropic, DefaultHttpxClient

client = Anthropic(
    timeout=httpx.Timeout(60.0, connect=5.0),
    http_client=DefaultHttpxClient(proxy="http://my.proxy.example"),
)

# After
import httpx2 as httpx
from anthropic import Anthropic, DefaultHttpxClient

client = Anthropic(
    timeout=httpx.Timeout(60.0, connect=5.0),
    http_client=DefaultHttpxClient(proxy="http://my.proxy.example"),
)

The aliasing trick keeps the rest of the file unchanged. Every httpx.Response, httpx.Request and httpx.Headers annotation in code that touches the SDK needs the same treatment, otherwise you end up with type hints pointing at a library the SDK no longer uses. A type checker catches these; running pyright or mypy after the upgrade is the single highest-value step in this whole migration.

If your codebase uses httpx elsewhere for its own reasons and you would rather not touch every import, httpx2 offers a global alias, which must run before any httpx import:

import httpx2
httpx2.alias_httpx()
import httpx  # now resolves to httpx2

Claude Code's own changelog entry notes the related consequence for its Python API migration path: "timeouts now use anthropic.Timeout."

Removed: the legacy Text Completions API

client.completions.create(), the /v1/complete endpoint, is gone. So are the Completion and CompletionCreateParams types, and the anthropic.HUMAN_PROMPT and anthropic.AI_PROMPT constants.

If you still have code doing string concatenation with HUMAN_PROMPT, this migration is not the real problem; that surface has been superseded for a long time. Move to client.messages.create().

Removed and renamed request parameters

Two changes here, and the first will surprise people.

temperature, top_p and top_k are removed from messages.create(), messages.stream() and messages.parse(). Remove them. If you are still calling an older model that genuinely accepts them, route them through extra_body:

client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Summarise this."}],
    extra_body={"temperature": 0.2},   # older models only
)

output_format as a dict becomes output_config:

# Before
client.beta.messages.create(
    ...,
    output_format={"type": "json_schema", "schema": Order.model_json_schema()},
)

# After
client.beta.messages.create(
    ...,
    output_config={"format": {"type": "json_schema", "schema": Order.model_json_schema()}},
)

messages.stream() still accepts output_format, but only as a type class, not a raw schema dict. Pass dicts through output_config instead.

.with_raw_response changed shape

This one fails at runtime rather than at import, which makes it the most likely to slip through a rushed upgrade.

On the sync client, .text and .content were properties. They are now methods:

response = client.messages.with_raw_response.create(...)

# Before
text = response.text
content = response.content

# After
text = response.text()
content = response.read()

On the async client, the raw-response accessors are now awaitable, including parse():

response = await client.messages.with_raw_response.create(...)

# Before
message = response.parse()

# After
message = await response.parse()
await response.text()
await response.read()
await response.json()

A missing await on parse() gives you a coroutine object where you expected a Message, and the traceback lands somewhere unhelpful downstream. Grep for with_raw_response and check every call site.

Removed helper arguments

OldNew
client.messages.parse(..., stream=True)client.messages.stream(..., output_format=Order)
tool_runner(compaction_control=...)Server-side context_management with betas=["compact-2026-01-12"]
messages.stream() with output_format as a raw dictType classes only; use output_config= for dicts

The tool_runner change is the interesting one: client-side compaction control moves to a server-side mechanism behind a beta flag. If you built your own trimming behaviour around compaction_control, that logic needs revisiting rather than mechanically porting.

Low-level request methods: body= becomes content=

If you make raw requests through the client, the keyword changed:

# Before
client.post("/v1/example", body=b"raw payload", cast_to=httpx.Response)

# After
client.post("/v1/example", content=b"raw payload", cast_to=httpx2.Response)

Header handling is now case-insensitive

Previously, a default_headers entry with different casing from an SDK-set header resulted in both being sent:

client = Anthropic(default_headers={"USER-AGENT": "my-app/1.0"})
# Before: sent User-Agent: Anthropic/Python ... AND USER-AGENT: my-app/1.0
# After:  sends only USER-AGENT: my-app/1.0

This is almost certainly the behaviour you wanted, but if anything downstream, a proxy, a WAF rule, an analytics pipeline, was keyed on the SDK's own header still being present, that assumption no longer holds.

Separately, bytes header values are no longer accepted. This previously worked despite being a type error:

# Before (worked, wrongly)
client.messages.create(..., extra_headers={"X-Signature": signature_bytes})

# After
client.messages.create(..., extra_headers={"X-Signature": signature_bytes.decode()})

Signature and HMAC code is the usual place this bites.

Bedrock: region is now required

AnthropicBedrock() used to fall back silently to us-east-1 when no region was configured. It now raises a ValueError:

client = AnthropicBedrock(aws_region="us-east-1")
# or set AWS_REGION / AWS_DEFAULT_REGION

Silent-default-to-a-region is exactly the kind of behaviour that produces a surprising cloud bill or a data-residency incident, so this is a good change, but it will break deployments that were relying on the fallback without knowing it. Check your container environment before you ship the upgrade.

Bedrock streaming also now skips unknown events such as amazon-bedrock-invocationMetrics rather than surfacing them.

Removed type aliases and exports

RemovedUse instead
anthropic.Transporthttpx2.BaseTransport
anthropic.ProxiesTypeshttpx2.Proxy
anthropic.types.beta.BetaBase64PDFBlockParamanthropic.types.beta.BetaRequestDocumentBlockParam
anthropic.lib.tools.agent_toolset.READ_MAX_BYTESanthropic.lib.tools.agent_toolset.DEFAULT_MAX_FILE_BYTES

Stream type checking also moved:

# Before (deprecated)
from anthropic import Stream
if isinstance(obj, Stream):
    ...

# After
from anthropic.lib.streaming import MessageStream
if isinstance(obj, MessageStream):
    ...

A migration checklist

Anthropic's own MIGRATION.md ends with a checklist, and it is a sensible running order:

[ ] Upgrade Python to >= 3.10
[ ] pip install --upgrade "anthropic>=1,<2"
[ ] Replace `import httpx` with `import httpx2 as httpx`
[ ] Update httpx.Response / httpx.Request type hints to httpx2
[ ] Move off the legacy Completions API
[ ] Remove temperature, top_p, top_k
[ ] Change output_format=dict to output_config={"format": {...}}
[ ] Update .with_raw_response calls to methods: .text(), .read()
[ ] Await async raw-response methods, including parse()
[ ] Replace deprecated helpers with server-side equivalents
[ ] Run pyright or mypy to catch what is left

That last line does more work than the rest combined. A large share of these changes are type-level, and a type checker finds them in seconds where reading diffs finds them in hours.

Letting Claude Code do it

Claude Code v2.1.239 added /claude-api upgrade for exactly this migration:

/claude-api upgrade

It comes from the bundled claude-api skill, which is an Agent Skill Anthropic writes and maintains, shipping with Claude Code rather than needing installation. The same skill already handled model migrations through /claude-api migrate, and the pattern is the same: it edits files, explains each change inline, and finishes with a list of items needing human verification.

Be honest with yourself about which parts of this migration an automated pass can actually own. Import rewrites, type annotation updates, .text to .text(), body= to content=, output_format to output_config: those are mechanical and a tool should get them right. The ones to review carefully:

  • Removing temperature. Whether a given call site should drop the parameter or route it through extra_body depends on which model it targets, and dropping it silently changes model behaviour.
  • The Bedrock region. A tool can add aws_region to a constructor. It cannot know which region your deployment was actually landing in when it defaulted.
  • compaction_control. Moving to server-side context_management is a design change, not a rename.
  • Header casing. Only you know whether something downstream depended on the old duplicate-header behaviour.

Run it on a branch. Read the diff. That is the same advice we give for /claude-api migrate, and it applies more here, because the failure mode is a behavioural change that passes type checking.

Should you upgrade now?

A fair question, and the honest answer depends on what you are running.

Upgrade sooner if you are on a supported Python version, your test suite is real, and you use type checking. The mechanical work is a couple of hours for most codebases and the checker catches the rest.

Wait if you are pinned to Python 3.9, if you have significant custom httpx transport or proxy code that will need genuine rework, or if you depend on compaction_control and have not yet worked out what the server-side equivalent looks like for your workload. Pinning anthropic>=0.125,<1 is a perfectly reasonable position for a few weeks. The 0.x line does not stop working the day 1.0 lands.

What you should not do is upgrade without running a type checker afterwards. Several of these changes, particularly the raw-response methods and the async await, will pass an import and fail in production.

Where to go next

Anthropic's MIGRATION.md is the authoritative document and worth reading in full before a large migration; this guide follows its structure but the original carries every code sample. For what the bundled skill doing the migration actually is, see Anthropic's open-source claude-api skill explained. If you are building on the newer hosted surface rather than the Messages API directly, Claude Managed Agents explained covers that. And for shipping skill folders to a production Claude API integration, how to use Agent Skills with the Claude API is the relevant guide. Browse the catalogue at getclaudeskills.com/skills.

Verified 24 August 2026 directly against the anthropic-sdk-python v1.0.0 release notes and MIGRATION.md on GitHub, and the Claude Code v2.1.239 changelog entry dated 21 August 2026.

Frequently asked questions