Skip to content
Mastering Claude

Home / The Claude API for builders

The Claude API for builders8 minApplication

Moving to Opus 5.5 without breaking your code

Moving from Claude Opus 5 to Claude Opus 5.5 is not just a matter of changing the identifier: four old settings now return a 400 error, and the notes written between two tool calls arrive empty until the code sets thinking.display.

Claude Opus 5.5, announced on 22 September 2026, is called claude-opus-5-5 in the API. The official page on what is new lists four breaking changes for code already running on Claude Opus 5, and a fifth change that makes no request fail but alters the shape of the response. Code that only changes the identifier is exposed to all five.

Four requests the API refuses

  • Thinking can no longer be switched off. A thinking field of type disabled, like a manual budget of type enabled with budget_tokens, returns a 400 error. The field is omitted, or takes the type adaptive, and depth is set with output_config.effort.
  • Tool forcing disappears. A tool_choice of type any or tool returns a 400 error, including on the endpoint that counts tokens. What remains is auto, the default, and none.
  • A thinking block is tied to its model and to the conversation: on accounts created from 31 August 2026, replaying it after a change to the system prompt, the tools or an earlier message returns a 400 error.
  • On the Claude API and Google Cloud, the computer_20251124 tool is refused in favour of the computer_toolset_20260801 toolset.

To replace forcing, the documentation advises keeping auto and setting strict: true on the tool. This setting constrains the arguments: when Claude calls the tool, its input respects the declared schema. It does not decide that the call will happen. For that, the message says in so many words when the tool applies. The schema must be complete, and each object in it carries additionalProperties: false. Here is a request accepted by Claude Opus 5 and refused by Claude Opus 5.5:

{
  "model": "claude-opus-5",
  "max_tokens": 1024,
  "thinking": { "type": "disabled" },
  "tools": [{
    "name": "find_customer",
    "description": "Retrieves a customer record from their number",
    "input_schema": {
      "type": "object",
      "properties": {
        "number": { "type": "string" }
      },
      "required": ["number"],
      "additionalProperties": false
    }
  }],
  "tool_choice": { "type": "tool", "name": "find_customer" },
  "messages": [{ "role": "user", "content": "Find the record for customer 4021" }]
}

The same request corrected for Claude Opus 5.5:

{
  "model": "claude-opus-5-5",
  "max_tokens": 1024,
  "output_config": { "effort": "low" },
  "tools": [{
    "name": "find_customer",
    "description": "Retrieves a customer record from their number",
    "input_schema": {
      "type": "object",
      "properties": {
        "number": { "type": "string" }
      },
      "required": ["number"],
      "additionalProperties": false
    },
    "strict": true
  }],
  "tool_choice": { "type": "auto" },
  "messages": [{ "role": "user", "content": "Find the record for customer 4021. Use the find_customer tool." }]
}

The change that returns no error

Between two tool calls, Claude Opus 5 wrote short notes in blocks of type text. Claude Opus 5.5 puts them in blocks of type thinking, and with the default setting, display: "omitted", their thinking field arrives empty. An interface that used to display these notes goes quiet, without the slightest error. Sorting blocks by their type field avoids mistaking a thinking block for the answer, but does not return the text: you also need to set thinking.display. The value "updates", in beta under the thinking-display-updates-2026-08-18 header, returns the notes alone; "summarized" mixes in the full summary of the reasoning, with no way to tell the two apart.

# request: "thinking": {"type": "adaptive", "display": "updates"}, beta header thinking-display-updates-2026-08-18
for block in response.content:
    if block.type == "thinking" and block.thinking:
        show(block.thinking)  # note written between two tool calls
    elif block.type == "text":
        show(block.text)

This sorting is only for display. In a tool loop, the assistant's message is sent back as is, thinking blocks included, even empty ones: the API rejects a block that has been modified, moved or removed.

The effort applied when the field is missing drops one notch, as the table shows. The per-token price goes down, as the figure puts it, but always-on thinking is billed in output tokens even when its text is not returned: the trade-off in the lesson on choosing a model has to be recalculated at the chosen effort. The tool declaration from the lesson on tools is the first thing affected, and an instruction written for the old behaviour ages, as the lesson on instructions that age shows.

Figure 1

What changes between Claude Opus 5 and Claude Opus 5.5, identifier replaced alone

Setting or behaviourOn Claude Opus 5On Claude Opus 5.5
Thinking disabled, thinking of type disabledAccepted at effort high or belowRefused, 400 error
Forced tool, tool_choice of type tool or anyAcceptedRefused, 400 error
computer_20251124 tool on the Claude API and Google CloudAccepted with the dedicated beta headerRefused, 400 error
Effort applied when the field is omittedhighmedium
Notes written between two tool callsBlocks of type textBlocks of type thinking, empty at the default display setting
Each row compares a setting or behaviour between the two models, for an otherwise identical request.
Figure 2

The price of Claude Opus 5.5 per million tokens

4dollars per million
input price of Claude Opus 5.5, against 5 dollars for Claude Opus 5
platform.claude.com, what is new in Claude Opus 5.5, 2026-09-28
20dollars per million
output price of Claude Opus 5.5, against 25 dollars for Claude Opus 5
platform.claude.com, what is new in Claude Opus 5.5, 2026-09-28
The input and output price of Claude Opus 5.5 at launch, compared in each label with that of Claude Opus 5.
Calibrate it yourself

A team migrates its integration from claude-opus-5 to claude-opus-5-5 by changing the model identifier in its code. This code walks through the blocks of each response, keeps those whose type field is text and displays their content. After the migration, the area of the interface that used to display the model's notes between two tool calls stays empty throughout the task, and every call returns a success code.

Write in one sentence what this situation establishes, and in one sentence what it does not establish.

What to remember
  • A manual thinking budget, type enabled with budget_tokens, is refused just like switching thinking off: effort becomes the only lever for depth.
  • The strict: true setting guarantees the shape of a called tool's arguments, and it is the message that must say when to call it.
  • Sorting blocks by type protects the reading of the response, and it is the thinking.display setting that makes the notes written between two tool calls readable.
  • Thinking blocks are sent back intact in a tool loop, including those whose text is empty.
  • The official migration guide lists each change by starting model, and its list for Claude Opus 5 fits in a single group.
Do this now

Open the code that calls the Claude API and look in it for the three patterns that cause a 400 error: thinking of type disabled or enabled, tool_choice of type any or tool, a tool of type computer_20251124. Fix each one according to the official migration guide. Then look, separately, for any reading of the response by position such as content[0].text: this pattern returns no error, it silently breaks the display. If your interface displays the notes written between two tool calls, set thinking.display to updates with the beta header thinking-display-updates-2026-08-18, and display the non-empty thinking blocks.

Check the source

Every datable claim in this lesson links here to the public text behind it. A source that does not open proves nothing.