Claude API docs in plain terms: the Messages API without the fluff
A short reference to the Claude Messages API: what is required, what is deprecated, how to read the response and errors. Examples target the gateway.
6 min · · API keys · development
The official Claude API docs are written in English and spread across a dozen pages, yet in practice almost everything comes down to one endpoint: POST /v1/messages. Below is a condensed guide to the Messages API (building with the Claude API): which fields are required, how roles and the response are structured, and what to know about streaming, tools, caching and errors. All examples target the Zukko gateway, but the Anthropic request format is the same everywhere. The primary source is Anthropic's documentation (API reference, the Messages page), and if anything here disagrees with it, trust the documentation, not this summary.
Claude API docs: a request on one screen
A minimal call looks like this:
curl https://api.zukko.pro/v1/messages \
-H "Authorization: Bearer fetch_your_key" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello, Claude"}]
}'Headers: anthropic-version (Zukko needs 2023-06-01, and SDKs set it for you), content-type and the key. The key can be sent as Authorization: Bearer fetch_... or as x-api-key, which the Anthropic SDK sends by default. With the official SDK, set base_url without /v1 (https://api.zukko.pro) because the SDK adds the path itself. Details and examples are in the Messages API reference.
Request body parameters
| Field | Required | What it is |
|---|---|---|
model | yes | model id, for example claude-sonnet-5-5 or claude-opus-5-5 |
max_tokens | yes | maximum tokens in the response |
messages | yes | list of turns with role and content |
system | no | system instruction: a string or an array of text blocks |
stop_sequences | no | strings at which the model stops |
stream | no | true turns on streaming output |
tools, tool_choice | no | tool definitions and the rule for choosing them |
thinking | no | reasoning configuration |
cache_control | no | marker for prompt caching |
metadata.user_id | no | an opaque identifier of your end user |
Two things to remember about max_tokens. First, it is a ceiling, not a target: the model may stop earlier. Second, it is also a ceiling on the price of the response. Example: on claude-sonnet-5-5 output costs $2 per 1M tokens, so with max_tokens: 1024 a single response cannot cost more than 1024 × 2 / 1,000,000 ≈ $0.002 (prices as of 18 October 2026).
What is deprecated: temperature, top_p, top_k
In Anthropic's reference these three parameters are marked deprecated. It says that models released after Claude Opus 4.6 do not support setting temperature: the value 1.0 is accepted for backward compatibility and any other value causes a 400 error. For top_p values of 0.99 and above are accepted, and for top_k any value is rejected. If your code always sends temperature=0.2, you will have to remove it for newer Claude models. Check the exact rules for your model in Anthropic's documentation.
Roles, system and prefill
messages uses only the user and assistant roles, and they should alternate. Consecutive turns with the same role are merged into one by the API. The system instruction goes not in messages but in the separate system field:
import anthropic
client = anthropic.Anthropic(
base_url="https://api.zukko.pro",
api_key="fetch_your_key",
)
message = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=1024,
system="Answer briefly and to the point.",
messages=[{"role": "user", "content": "What is idempotency?"}],
)
print(message.content[0].text)If the last turn in the list has the assistant role, the response continues its text. This is called prefill. According to the documentation, on models that do not support prefill such a request returns 400.
Reading the response
content in the response is a list of blocks, not a string. Usually it is a type: "text" block, but tool and reasoning blocks are possible. So message.content[0].text works for simple cases, but in general iterate over the blocks and check type. Then look at:
stop_reason:end_turn(the model finished),max_tokens(hit the ceiling, the answer is cut off),stop_sequence,tool_use(the model asks you to call a tool);usage:input_tokens,output_tokensand, if the cache was used,cache_creation_input_tokensandcache_read_input_tokens.
Streaming
With stream: true the response arrives as server-sent events. In Python the SDK helper is more convenient because it assembles the text for you:
with client.messages.stream(
model="claude-sonnet-5-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Write a short toast"}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)An error in the middle of a stream can arrive after a 200 response, as a separate error event, so status codes will not help here: handle the events. For requests that take long to generate, Anthropic recommends streaming.
Tools
Tools are described in tools: a name, a description and a JSON schema of the input in input_schema. If the model decides to call a tool, the response comes with stop_reason: "tool_use" and a tool_use block. You run the function yourself and return the result in the next user turn with a tool_result block. The whole loop is covered in the article on tool use.
Prompt caching and token counting
To reuse a long repeating prefix (for example a large system), attach cache_control: {"type": "ephemeral"} to a block. According to Anthropic's documentation, the cache lives 5 minutes by default, there is also a 1-hour option via the ttl parameter, and prefixes that are too short are not cached, without an error. Check whether the cache worked in the usage fields. For Claude the gateway sees cache reads and writes only in the Anthropic format, that is, via /v1/messages. How this affects price is covered in the article Claude: Messages or Chat Completions.
You can learn the size of a request before sending it through POST /v1/messages/count_tokens with the same model, system, messages and tools. The response contains input_tokens. See the count tokens reference.
Error codes
An error always arrives as a JSON object with type: "error" and error.type, error.message, plus a request_id. The main Anthropic codes: 400 invalid_request_error, 401 authentication_error, 403 permission_error, 404 not_found_error, 413 request_too_large, 429 rate_limit_error, 500 api_error, 529 overloaded_error. Through the gateway there are additional causes:
| Code | Cause at Zukko |
|---|---|
| 401 | invalid key |
| 402 | insufficient balance |
| 403 | model_not_allowed_for_key: the model is not allowed for this key |
| 404 | model_not_found: unknown model name |
| 429 | the key's daily or monthly limit is exhausted, or a restriction at the model provider |
| 503 | provider unavailable or model disabled (model_disabled) |
For 429 and 5xx the official SDK retries twice by default with a delay. With key limits, retries are pointless: raise the limit in the dashboard. See GET /v1/models for the models available to your key.
To go through the examples on your own key, create one in the dashboard and put it into the requests above.
FAQ
How does the Messages API differ from Chat Completions?
The format is different: Anthropic puts the system instruction in a separate system field, max_tokens is required, and the response consists of content blocks. The gateway accepts both formats for any model, but the cache discount for Claude comes only with the Anthropic format.
Is max_tokens required?
Yes, in the Messages API it is a required field. Without it the request returns 400.
Why does a request with temperature fail on a new model?
Anthropic marked temperature, top_p and top_k as deprecated, and for models after Opus 4.6 values other than the permitted ones are rejected. Remove the parameters from the request.
Where can I see current models and prices?
GET https://api.zukko.pro/v1/models or the Models page in the dashboard. Prices in this article are as of 18 October 2026 and may change.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- Your Own Neural Network Proxy on Node.js: Keep the API Key Off the FrontendA small Express server between your frontend and the model API: the key stays on the server, and models, request size and rate are capped.
- DeepSeek API in Python: Requests, Streaming, JSON and Error HandlingReady code for DeepSeek V4.1 Flash and V4 Pro on the OpenAI SDK: a request, streaming, JSON parsing and careful error handling.
- Gemini API in Python: requests via the OpenAI SDK and OpenAI formatA working Gemini API example in Python with no extra library: change base_url in the OpenAI SDK, add streaming and JSON, and compare with google-genai.
- Anthropic SDK for Python: base_url, key and a first request via a gatewayThe official anthropic package for Python just needs a different address. We cover base_url, the key, streaming, token counting, caching and errors.