Stop reasons and token usage

Claude API · Essentials · 8 min

stop_reason tells you whether an answer is complete, and usage is how you track spend.

Besides content, the response tells you why Claude stopped and how much it used.

stop_reason is a short string:

  • end_turn: Claude finished naturally. This is the normal case.
  • max_tokens: Claude ran into your max_tokens ceiling, so the answer is cut off.
  • stop_sequence: Claude produced one of the custom strings you passed in stop_sequences.
  • tool_use: Claude wants your code to run a tool (covered later).
  • refusal: Claude declined for safety reasons.

Always check it. Treating a max_tokens answer as complete is a classic bug: half a JSON object, or a summary that stops mid-list. Either raise max_tokens or ask for a shorter answer.

usage counts tokens. input_tokens is what you sent and output_tokens is what Claude wrote. You pay per token, with output usually priced higher than input, so these two numbers are the basis of every cost estimate. Later lessons add more fields here, such as tokens read from the prompt cache.

The response also has an id (like msg_...) and the model that answered. When something goes wrong and you contact support, the request id in message._request_id is what they will ask for, so log it alongside errors.

Example

import anthropic

client = anthropic.Anthropic()
msg = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=30,                      # deliberately small
    messages=[{"role": "user", "content": "Explain photosynthesis in detail."}],
)

print(msg.stop_reason)                  # max_tokens -> answer was cut off
print(msg.usage.input_tokens, msg.usage.output_tokens)
print(msg._request_id)                  # req_... for support tickets

if msg.stop_reason == "max_tokens":
    print("Truncated: raise max_tokens or ask for less.")

Remember

  • Check stop_reason; max_tokens means the answer is incomplete
  • usage.input_tokens and usage.output_tokens drive cost
  • Log _request_id for debugging

Watch out for

  • Parsing a truncated reply as if it were complete.

Check yourself

  1. A reply ends mid-sentence and stop_reason is "max_tokens". What is the fix?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: platform.claude.com/docs/en/build-with-claude/handling-stop-reasons