Anthropic Python SDK: count_tokens Became a Stable API in 0.75.0 — A Migration Guide

Anthropic Python SDK: count_tokens Became a Stable API in 0.75.0 — A Migration Guide

Hello!

Today's topic is the Anthropic Python SDK, a convenient way to work with the Anthropic Claude API.

A fairly significant change landed about two weeks ago, so let's walk through it.

Introduction

"Wait, client.count_tokens() stopped working..."

You updated the Anthropic Python SDK, and the token-counting code that had been working fine suddenly started throwing errors. Many LLM engineers have probably run into exactly this.

When you develop LLM-integrated services like our Bestllam, accurately knowing how many tokens your users are actually consuming becomes critically important. Billing calculations, context window management, and usage visibility for users — token counting underpins the core of the service. So when this feature suddenly breaks, the impact is far from trivial.

That is exactly why, if you run a production service, you should never casually bump the SDK version with a quick pip install.

Now, about the Anthropic Python SDK: there was in fact a major change between 0.74.1 (released November 20, 2025) and 0.75.0 (released November 25, 2025).

Even before that, SDK version 0.39.0 (released November 5, 2024) had already overhauled the token counting feature significantly, so this article covers the changes starting from that point as well.
Let's look at the background behind these changes and how to migrate to the new API.

1. What Changed

The deprecated API

In version 0.38.x and earlier, you retrieved token counts like this.

# Old API (0.38.x and earlier) - no longer works
client = Anthropic()
token_count = client.count_tokens("Hello, world")

It was a simple, easy-to-use API, but in version 0.39.0 both client.count_tokens() and client.get_tokenizer() were removed entirely.

Calling them after the update raises AttributeError.

Why was it removed? To support multimodality

The reason lies in Claude's evolution. From Claude 3 onward, the models can understand images and PDFs.The old API was text-only, so it could not count tokens for multimodal content.

It was also difficult to accurately account for all the tokens consumed in a real API call, such as system prompts and tool definitions.

Rather than maintaining half-hearted backward compatibility, Anthropic appears to have opted for a full migration to the new design.

2. How to Use the New API

The basics

The new API is client.messages.count_tokens(). It accepts nearly the same parameters as messages.create().

# New API (0.75.0 and later)
from anthropic import Anthropic

client = Anthropic()

response = client.messages.count_tokens(
    model="claude-sonnet-4-5-20250929",
    messages=[
        {"role": "user", "content": "Hello, world"}
    ]
)

print(response.input_tokens)  # token count

There are three important differences, though.

First, the model parameter is now required, because tokenization differs from model to model.

Second, instead of passing text directly, you pass a message structure. Finally, the return value is now an object rather than an integer, and you read the token count from .input_tokens.

System prompts and tools are counted too

The strength of the new API is that you can count tokens using the exact same structure as a real API call.

response = client.messages.count_tokens(
    model="claude-sonnet-4-5-20250929",
    system="You are a helpful assistant.",
    messages=[
        {"role": "user", "content": "Hello"},
        {"role": "assistant", "content": "Hello! How can I help you?"},
        {"role": "user", "content": "What's the weather like?"}
    ],
    tools=[
        {
            "name": "get_weather",
            "description": "Gets the weather",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {"type": "string"}
                },
                "required": ["location"]
            }
        }
    ]
)

You can read the token count from response.input_tokens

# Get the token count
print(response.input_tokens)  # e.g., 142

System prompt, conversation history, tool definitions — every token is counted accurately.

Images and PDFs are supported as well

You can also count tokens for multimodal content. This is arguably the most important point.

import base64

with open("image.png", "rb") as f:
    image_data = base64.standard_b64encode(f.read()).decode("utf-8")

response = client.messages.count_tokens(
    model="claude-sonnet-4-5-20250929",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": image_data
                    }
                },
                {"type": "text", "text": "Please describe this image"}
            ]
        }
    ]
)

print(response.input_tokens)  # returns a token count that reflects the image size

3. Migration Steps

Step 1: Update the SDK

First, update the SDK to 0.75.0 or later (the latest as of December 9, 2025, when this post was written).

pip install anthropic>=0.75.0

As mentioned at the beginning, between 0.39.0 and 0.74.x this feature was provided in beta as client.beta.messages.count_tokens().

# Beta API (0.39.0 - 0.74.x) - deprecated as of 2025/12/9
response = client.beta.messages.count_tokens(
    betas=["token-counting-2024-11-01"],  # a beta header was required
    model="claude-3-5-sonnet-20241022",
    messages=[
        {"role": "user", "content": "Hello"}
    ]
)
print(response.input_tokens)

From 0.75.0 onward, client.messages.count_tokens() is available as a stable API. The beta header is no longer needed either.

# Stable API (0.75.0 and later) - current recommendation
response = client.messages.count_tokens(
    model="claude-sonnet-4-5-20250929",
    messages=[
        {"role": "user", "content": "Hello"}
    ]
)
print(response.input_tokens)

Step 2: Rewrite your code

Here is how the old code maps to the new code.

# Old: simple text
count = client.count_tokens("Hello")

# New: pass a message structure
response = client.messages.count_tokens(
    model="claude-sonnet-4-5-20250929",
    messages=[{"role": "user", "content": "Hello"}]
)
count = response.input_tokens

Preparing a helper function like this makes the migration easier.

def count_tokens(client, text, model="claude-sonnet-4-5-20250929"):
    """Helper function that feels like the old API"""
    response = client.messages.count_tokens(
        model=model,
        messages=[{"role": "user", "content": text}]
    )
    return response.input_tokens

Step 3: Update requirements.txt

For production environments, we recommend pinning the version explicitly.

anthropic>=0.75.0,<1.0.0

4. FAQ

"Is it a problem to stay on 0.39.0?"

It still works on 0.39.0, but you have to call it as client.beta.messages.count_tokens() with the beta header specified. From 0.75.0 onward you get a stable, official API, so we recommend upgrading.

"Am I billed for the API call?"

count_tokens counts as an API request, but there is no token-based billing. It may, however, count against your rate limits, so be careful when sending large volumes of requests.

"Can I use it asynchronously?"

Yes. Use the AsyncAnthropic client and call the same method with await.

from anthropic import AsyncAnthropic

client = AsyncAnthropic()
response = await client.messages.count_tokens(
    model="claude-sonnet-4-5-20250929",
    messages=[{"role": "user", "content": "Hello"}]
)

Closing Thoughts

The token counting API change came along with Claude's big evolutionary step into multimodality. Multimodality itself felt like a natural progression, so it was somewhat surprising to realize the API had been designed around only the spec in front of it at the time (text-only exchanges).

The new API can compute accurate token counts covering not just text but also images, PDFs, and tool definitions.

The migration takes a bit of work, but it enables more accurate, more practical token management. This is a good opportunity to update.

See you next time!

Read more