Claude API Max Tokens Parameter: Best Practices
If you've ever gotten a response from Claude that stops mid-sentence, or paid more than expected for a short answer, there's a good chance the max_tokens parameter is the culprit. This single field controls both the ceiling on response length and, indirectly, your output cost and latency — so getting it right matters more than most developers assume.
The short answer: max_tokens is a required parameter that sets the upper bound on how many tokens Claude is allowed to generate in a single response. It does not guarantee that many tokens will be produced — Claude stops earlier if it reaches a natural end (stop_reason: "end_turn"). It only guarantees Claude won't go past that number. If Claude is still generating when it hits the limit, the response is cut off and stop_reason becomes "max_tokens". The rest of this article covers how to pick good values, how to detect truncation, and how to tune this per use case instead of hardcoding a number and hoping.
What max_tokens Actually Does
Every Claude API request needs a max_tokens value. It's not a suggestion or a soft target — it's a hard cap on the output. Under the hood:
- Input tokens (your prompt, system message, tool definitions, conversation history) are counted separately and don't count against
max_tokens. - Output tokens (what Claude generates) are capped by
max_tokens. - Total context window (input + output) still has to fit within the model's overall limit, so a very large
max_tokenscombined with a long prompt can push you against that ceiling.
A common mistake is treating max_tokens as a cost control knob by setting it low across the board. That works, but it also risks silent truncation — the model doesn't know ahead of time how long its answer "should" be, so if you cut it off too early you get incomplete JSON, broken code blocks, or sentences that stop mid-word.
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "Summarize this changelog in 3 bullet points."}
]
}'
Choosing a Value: Match It to the Task, Not a Fixed Default
There's no universal "correct" max_tokens. The right value depends entirely on what you're asking Claude to do:
- Short, structured outputs (classification labels, single JSON objects, yes/no answers): 100–300 tokens is usually plenty. Setting this low also catches bugs early — if your prompt is accidentally generating essays instead of labels, you'll notice immediately.
- Conversational replies, summaries, explanations: 500–1500 tokens covers most cases without over-provisioning.
- Long-form generation (articles, detailed reports, multi-file code generation): 2000–4096+ tokens, depending on the model's maximum output limit. Check current model docs for the hard ceiling, since it varies by model version.
- Tool use and agentic loops: leave enough room for both the tool call payload and the final synthesized answer after tool results come back. If you're chaining tool calls, see /docs/tools for how multi-step responses consume the token budget across turns.
A practical rule: estimate the expected output length, add 20–30% headroom, and use that as your max_tokens. Don't just set it to the model's absolute maximum by default — that increases worst-case latency and gives a buggy prompt more room to run away.
Detecting and Handling Truncation
Always check stop_reason in the response, not just whether a response came back successfully.
{
"stop_reason": "max_tokens",
"usage": { "input_tokens": 142, "output_tokens": 1024 }
}
If stop_reason is "max_tokens", the content is incomplete. Depending on the use case, you have a few options:
- Increase max_tokens and retry — simplest fix if you have headroom in the context window.
- Continue the generation — send the partial response back as context and ask Claude to continue from where it left off. This works well for long-form content but adds a request round-trip.
- Redesign the prompt — if truncation happens often, the model may be padding with unnecessary preamble before getting to the actual answer. Tighter instructions ("respond with only the JSON object, no explanation") often shrinks output length more reliably than raising the cap.
For streaming responses, check the final event's stop reason the same way — truncation detection doesn't change whether you're using the standard endpoint or SSE streaming (see /docs/streaming if you're building a token-by-token UI).
max_tokens and Cost
Output tokens are typically priced higher per token than input tokens across most Claude models, so max_tokens has a direct relationship to your bill — but only as a ceiling, not as a guaranteed charge. You're billed for tokens actually generated, not the configured maximum. Setting max_tokens to 4096 "just in case" doesn't cost you anything extra if Claude naturally stops at 300 tokens. The real cost risk is the opposite: a loop or agent that keeps hitting the max and retrying with ever-larger limits, silently escalating spend.
If you're running Claude access through SubToAPI, every request's usage block — input and output token counts — is captured automatically and surfaced in your dashboard alongside your sub_live_ key activity, so you can see exactly where max_tokens settings are driving cost without building your own logging. Check /docs/messages for the full request/response shape, or start with /docs/quickstart if you're setting up your first integration.
A Few Concrete Recommendations
- Set it explicitly per endpoint or prompt template, not once globally. A support-bot reply and a code-generation feature should not share the same
max_tokensvalue. - Log stop_reason in production, even if you don't act on it immediately. It's the cheapest signal you have for whether your limits are too tight.
- Leave a buffer for tool use, since tool call JSON and the model's reasoning around it both consume the output budget.
- Re-evaluate after model upgrades. Newer model versions can be more or less verbose by default, which changes what a "safe"
max_tokensvalue looks like for the same prompt.
Tuning max_tokens well is less about finding one magic number and more about treating it as part of your prompt design — reviewed and adjusted alongside the prompt itself, not set once and forgotten.
Questions
Does a higher max_tokens make responses longer? No. It only raises the ceiling. Claude still stops naturally at end_turn if it finishes before reaching the limit — a higher value just reduces the risk of truncation.
What happens if max_tokens is too low? The response gets cut off mid-generation, stop_reason returns as "max_tokens", and you may receive incomplete JSON, broken code, or truncated sentences that need a retry or continuation.
Am I charged for the full max_tokens value even if the response is shorter? No. Billing is based on actual output tokens generated, not the configured maximum — max_tokens is a limit, not a reserved or guaranteed charge.