DEV Community

Super Lewis
Super Lewis

Posted on

Claude Sonnet 5.5 and Haiku 5.5 in Python: Two SDKs, Prompt Caching and Haiku's 100K Pricing Cliff

Short answer: call claude-haiku-5-5 for classification, extraction, routing and summaries, and claude-sonnet-5-5 for multi-step coding and long tool loops. Both work through the Anthropic SDK and, via a gateway, the OpenAI SDK. Keep each Haiku 5.5 prompt at or under 100,000 tokens, because above that every rate on the request is billed at five times.

Claude Sonnet 5.5 (released 28 September 2026) and Claude Haiku 5.5 (released 7 October 2026) are Anthropic's mid and small tiers of the Claude 5.5 family. Both have a 1M-token context window, 128K max output, text and image input, and adaptive thinking that is on by default. Anthropic's list prices are $2 / $10 per million input / output tokens for Sonnet 5.5 and $0.10 / $0.50 for Haiku 5.5.

Disclosure: the base URL in the examples belongs to apimodels.app, the API gateway I work on. Both models there run on more than one upstream channel with automatic failover, and failed requests are not charged. The snippets follow the request shapes in Anthropic's documentation, but I did not run them for this post, so check the output on your side.

What you need

  • Python 3.10 or later
  • pip install anthropic openai requests (any recent versions; newer request fields go through extra_body, so you do not depend on a specific SDK release)
  • An API key in APIMODELS_API_KEY. If you call Anthropic directly instead, drop the base_url lines and use your Anthropic key.

Which model for which call

Job Model Why
Ticket or intent classification, routing Haiku 5.5 Short prompts, huge volume, 20x lower list price
Field extraction, summaries, context compaction Haiku 5.5 Anthropic's stated home ground for Haiku 5.5
Subagent steps inside a coding agent Haiku 5.5 Anthropic: "pairs well with Opus 5.5 and Sonnet 5.5 as a subagent"
Multi-file coding, debugging, long tool loops Sonnet 5.5 Terminal-Bench 4.0: 70.6% against Haiku 5.5's 39.2% (Anthropic's Haiku launch table)
Prompts above 100K tokens Either Haiku bills them at 5x, but still a quarter of Sonnet's list price per token; decide on quality

Step 1: Call Haiku 5.5 with the Anthropic SDK

This is a ticket classifier. Effort is set to low because the job needs a label, not a chain of reasoning.

import os
import anthropic

client = anthropic.Anthropic(
    base_url="https://api.apimodels.app",          # no /v1 here; the SDK adds /v1/messages
    api_key=os.environ["APIMODELS_API_KEY"],
)

msg = client.messages.create(
    model="claude-haiku-5-5",
    max_tokens=4000,                                 # thinking tokens count toward this
    system="Classify the ticket as billing, bug, feature or other. Reply with the label only.",
    messages=[{"role": "user", "content": "I was charged twice for the same top-up."}],
    extra_body={"output_config": {"effort": "low"}},
)

# Haiku 5.5 can open with thinking blocks even if you never asked for thinking,
# so pick text blocks by type, never content[0].
label = "".join(b.text for b in msg.content if b.type == "text").strip()
print(label, msg.usage.input_tokens, msg.usage.output_tokens)
Enter fullscreen mode Exit fullscreen mode

Three details matter here. There is no temperature: on Haiku 5.5 Anthropic only accepts temperature 1 or top_p 0.99, and any top_k is a 400. max_tokens is generous because thinking tokens count toward it, and a small value can stop the response after the thinking block with no text at all. And the request ends with a user turn: Haiku 5.5 rejects an assistant prefill even with thinking off.

Step 2: Call Sonnet 5.5 with the OpenAI SDK

If your codebase is built on the OpenAI SDK, point it at the gateway's OpenAI-compatible endpoint and change only the model string.

from openai import OpenAI

oai = OpenAI(
    base_url="https://api.apimodels.app/v1",
    api_key=os.environ["APIMODELS_API_KEY"],
)

resp = oai.chat.completions.create(
    model="claude-sonnet-5-5",
    reasoning_effort="medium",                       # mapped to Anthropic's effort setting
    messages=[
        {"role": "system", "content": "You are a senior Python reviewer."},
        {"role": "user", "content": "Find the race condition in this function:\n..."},
    ],
)
print(resp.choices[0].message.content)
Enter fullscreen mode Exit fullscreen mode

On this endpoint the gateway does three translations worth knowing. If you leave out max_tokens, it fills in the model's own output ceiling instead of a small default; until 28 September it used 4,096, which cut long code files off mid-function. It drops temperature, top_p and top_k for both 5.5 models, so clients that send a default temperature do not hit Anthropic's 400. And reasoning_effort becomes Anthropic's effort level.

For tools on Sonnet 5.5, keep tool_choice at auto and set strict: true on the function. Anthropic rejects forced tool use on this model with tool_choice: type "tool" and "any" are not supported for this model., and its migration guide recommends auto plus strict instead.

Step 3: Cache the prefix you send every time

Prompt caching pays off on anything you repeat: a long system prompt, a policy document, a repository summary. The minimum cacheable prompt on both models is 512 tokens.

POLICY = open("refund_policy.md").read()   # a few thousand tokens, identical on every call

def ask(question: str):
    return client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=8000,
        system=[{"type": "text", "text": POLICY, "cache_control": {"type": "ephemeral"}}],
        messages=[{"role": "user", "content": question}],
    )

for q in ["Can a used top-up be refunded?", "How long does a refund take?"]:
    u = ask(q).usage
    print("write:", u.cache_creation_input_tokens, "read:", u.cache_read_input_tokens, "new:", u.input_tokens)
Enter fullscreen mode Exit fullscreen mode

Expect the first call to report a cache write and the second, within five minutes, a cache read. When we tested this pattern on Sonnet 5.5 at launch, three calls with the same prefix gave one write and two reads.

Through apimodels.app, a cache read costs a tenth of fresh input on both models: $0.12 per million on Sonnet 5.5 (input $1.20, cache write $1.50) and $0.009 on Haiku 5.5 (input $0.09, cache write $0.1125). Every repeated prefix that hits the cache is billed at that rate instead of the input rate.

Step 4: Price the 100K cliff before it prices you

Anthropic's rule for Haiku 5.5: if a request's prompt is over 100,000 tokens, counting new input, cache reads and cache writes, every rate on that request is multiplied by five, output included. Sonnet 5.5 has no such step anywhere in its 1M window.

This function reproduces the rule with apimodels.app prices as of 17 October 2026 (swap in Anthropic's list prices if you call them directly; the shape is identical):

# USD per 1M tokens, apimodels.app, as of 2026-10-17
PRICES = {
    "claude-sonnet-5-5": {"in": 1.20, "out": 6.00, "cache_read": 0.12,  "cache_write": 1.50},
    "claude-haiku-5-5":  {"in": 0.09, "out": 0.45, "cache_read": 0.009, "cache_write": 0.1125},
}

def request_cost(model, fresh_in, out, cache_read=0, cache_write=0):
    p = PRICES[model]
    prompt = fresh_in + cache_read + cache_write
    mult = 5 if model == "claude-haiku-5-5" and prompt > 100_000 else 1
    return mult * (fresh_in * p["in"] + out * p["out"]
                   + cache_read * p["cache_read"] + cache_write * p["cache_write"]) / 1_000_000
Enter fullscreen mode Exit fullscreen mode

Running it on a few request shapes gives:

Request Haiku 5.5 Sonnet 5.5
99K prompt, 1K output $0.00936 $0.12480
101K prompt, 1K output $0.04770 $0.12720
Same 101K split into two 50.5K requests $0.01000 not needed
150K prompt (140K cache read + 10K new), 2K output $0.01530 $0.04080

Read it in three ways. Two thousand extra tokens multiply the Haiku request by 5.1. Splitting the job into two prompts under the line cuts it by about 79% (you pay for a merge step on top). And caching does not get you back under the threshold, because cache reads count toward it.

What the table does not say is "switch to Sonnet". Over the cliff, Haiku 5.5 is still 37.5% of Sonnet 5.5's price for the same request here, and a quarter of it at Anthropic's list. Move a long-prompt job to Sonnet when Haiku's answers are not good enough, not to save money.

To catch the cliff in production, log the prompt size from every response:

def prompt_tokens(u):
    return u.input_tokens + (u.cache_read_input_tokens or 0) + (u.cache_creation_input_tokens or 0)

if prompt_tokens(msg.usage) > 100_000:
    print("billed at 5x:", prompt_tokens(msg.usage), "prompt tokens")
Enter fullscreen mode Exit fullscreen mode

Verify what you were billed

Every response from the gateway carries an x-apimodels-request-id header, and non-streaming responses also carry x-apimodels-cost. The record endpoint returns the settled amount and the token usage behind it.

import requests

raw = client.messages.with_raw_response.create(
    model="claude-haiku-5-5",
    max_tokens=1000,
    messages=[{"role": "user", "content": "Summarise: ..."}],
)
msg = raw.parse()
rid = raw.headers.get("x-apimodels-request-id")
print("charged now:", raw.headers.get("x-apimodels-cost"))

rec = requests.get(
    f"https://api.apimodels.app/v1/records/{rid}",
    headers={"Authorization": f"Bearer {os.environ['APIMODELS_API_KEY']}"},
).json()["data"]
print(rec["settled"], rec["credits"], rec["currency"], rec["usage"])
Enter fullscreen mode Exit fullscreen mode

If the cost does not match your own request_cost, compare rec["usage"] with what you assumed: thinking tokens in the output and the cache split are the usual differences.

Common errors

  • tool_choice: type "tool" and "any" are not supported for this model. Sonnet 5.5 does not allow forced tool use. Use auto with strict: true, and say in the prompt when the tool applies.
  • 400 on thinking: {"type": "disabled"} (Sonnet 5.5). Send {"type": "between_tools"} instead, at high effort or below.
  • 400 on temperature, top_p or top_k on the native endpoint. Remove them; steer with the prompt.
  • 400 on a trailing assistant message (Haiku 5.5). Prefill is gone; end with a user turn and use structured outputs for format.
  • stop_reason: "max_tokens" with no text. Thinking used the whole limit. Raise max_tokens or lower effort.
  • IndexError or empty string from content[0].text. The first block is a thinking block. Filter by type.
  • prompt is too long: ~3,062,816 input tokens (estimated) exceeds the 1,000,000-token context window for claude-haiku-5-5. The gateway rejects prompts it estimates are beyond the 1M window before sending them. Split the input first.
  • Streaming UI goes silent between tool calls (Sonnet 5.5). Notes between tool calls arrive as thinking blocks whose text is empty by default. Set thinking.display or use between_tools.

Where apimodels.app fits

apimodels.app is a multi-model API gateway: one API key, a native Anthropic Messages endpoint and an OpenAI-compatible endpoint for more than 140 image, video, audio and language models. Sonnet 5.5 and Haiku 5.5 each have more than one upstream channel with automatic failover, failed requests are not charged, and every call can be reconciled with GET /v1/records/{id} as in the last step. Prices as of 17 October 2026 are $1.20 / $6.00 for Sonnet 5.5 (60% of list) and $0.09 / $0.45 for Haiku 5.5 (90% of list). The records API docs show the full response.

Skip it if you need Anthropic's Message Batches API (there is no batch endpoint), or if you need a contract or data processing agreement with Anthropic itself.

Limits

  • The code is written to Anthropic's documented request shapes and was not executed for this post.
  • Prices and behaviour were checked on 17 October 2026. Re-check Anthropic's pricing page and the gateway's model pages before you plan a quarter's spend on these numbers.

Which of your calls would you move to Haiku 5.5 first, and how are you keeping prompts under the 100K line?

Written with AI assistance from Anthropic's documentation and apimodels.app's published prices, then checked against both before publishing.

Top comments (0)