API reference
Claude Messages API
Headers, parameters, request and response examples, SSE stream events and prompt caching for POST /v1/messages. Same format as the Anthropic Messages API; the official SDK works after changing base_url. Verified on this site.
POST /v1/messages is Anthropic's native API format. Code written with the official Anthropic SDK runs once you set the base URL to https://open.tutujin.com and use a key from this site; native parameters such as thinking, tool use and cache_control are passed to the model unchanged. We have verified this endpoint on this site.
https://open.tutujin.com/v1/messagesHeaders
| Header | Required | Description |
|---|---|---|
x-api-key | One of the two | An API key from the console (sk-...). The Anthropic SDK uses this header by default |
Authorization | One of the two | Bearer sk-..., as an alternative to x-api-key |
anthropic-version | Yes | API version: 2023-06-01 |
content-type | Yes | application/json |
anthropic-beta | No | Turns on Anthropic beta features; relayed as-is, effect depends on the model |
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model name, e.g. claude-sonnet-5-5 |
max_tokens | integer | Yes | Most tokens to generate. Required; leaving it out returns a 400 |
messages | array | Yes | The conversation. role is user or assistant, and the first message must be user |
system | string or array | No | System prompt, at the top level rather than inside messages |
temperature | number | No | 0 to 1, default 1. Lower values give steadier answers |
top_p | number | No | Nucleus sampling; tune this or temperature, not both |
top_k | integer | No | Sample only from the K most likely tokens |
stop_sequences | array | No | Stop generating when one of these strings appears |
stream | boolean | No | true returns server-sent events |
tools | array | No | Tool definitions, each with name, description and input_schema (JSON Schema) |
tool_choice | object | No | {"type": "auto"}, {"type": "any"}, or {"type": "tool", "name": "get_weather"} for a specific tool |
thinking | object | No | Extended thinking, e.g. {"type": "enabled", "budget_tokens": 2048}; budget_tokens must be below max_tokens. Supported forms per model follow Anthropic's documentation |
metadata | object | No | e.g. {"user_id": "u_123"}, your end-user identifier for abuse investigations |
The messages array
content is a string or an array of content blocks. Common block types are text, image, tool_use (a tool call from the model) and tool_result (the result you send back). Image plus text looks like this:
{
"role": "user",
"content": [
{
"type": "image",
"source": { "type": "base64", "media_type": "image/png", "data": "iVBORw0KGgo..." }
},
{ "type": "text", "text": "How many rows does the table in this image have?" }
]
}Request example
curl https://open.tutujin.com/v1/messages \
-H "x-api-key: $TUTUJIN_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5-5",
"max_tokens": 1024,
"system": "You are a careful legal assistant. Cite the contract clause numbers you rely on.",
"messages": [
{"role": "user", "content": "The penalty is set at 30% of the contract value. What are the risks?"}
]
}'import os
import anthropic
client = anthropic.Anthropic(
base_url="https://open.tutujin.com",
api_key=os.environ["TUTUJIN_API_KEY"],
)
message = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=1024,
system="You are a careful legal assistant. Cite the contract clause numbers you rely on.",
messages=[{"role": "user", "content": "The penalty is set at 30% of the contract value. What are the risks?"}],
)
print(message.content[0].text)
print(message.usage)import Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic({ baseURL: 'https://open.tutujin.com', apiKey: process.env.TUTUJIN_API_KEY })
const message = await client.messages.create({
model: 'claude-sonnet-5-5',
max_tokens: 1024,
system: 'You are a careful legal assistant. Cite the contract clause numbers you rely on.',
messages: [{ role: 'user', content: 'The penalty is set at 30% of the contract value. What are the risks?' }],
})
console.log(message.content[0].text)
console.log(message.usage)The Anthropic SDK sends x-api-key and anthropic-version for you and appends /v1/messages to the base URL, so the base URL is just the site root.
Response example
{
"id": "msg_...",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-5-5",
"content": [
{ "type": "text", "text": "A 30% penalty is high and a court may treat it as excessive..." }
],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 52,
"output_tokens": 210,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0
}
}| Field | Description |
|---|---|
content | Content blocks: text, thinking (with extended thinking on) and tool_use |
stop_reason | end_turn finished normally; max_tokens hit the limit; stop_sequence hit a stop string; tool_use wants you to run a tool |
usage.input_tokens | Input tokens not served from cache, billed at the input price |
usage.output_tokens | Output tokens including thinking, billed at the output price |
usage.cache_creation_input_tokens | Input tokens written to the cache, billed at the cache-write price |
usage.cache_read_input_tokens | Input tokens read from the cache, billed at the cache-read price |
Streaming
With "stream": true the server returns Anthropic's SSE events. New text is in delta.text of content_block_delta events, and message_delta carries the stop reason and final output tokens:
event: message_start
data: {"type":"message_start","message":{"id":"msg_...","type":"message","role":"assistant","content":[],"usage":{"input_tokens":52,"output_tokens":1}}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"A 30% penalty"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":210}}
event: message_stop
data: {"type":"message_stop"}The SDKs wrap these events, so you can read the text stream directly:
with client.messages.stream(
model="claude-sonnet-5-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Write a 60-word product description"}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print("\n", stream.get_final_message().usage)const stream = client.messages.stream({
model: 'claude-sonnet-5-5',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Write a 60-word product description' }],
})
stream.on('text', (text) => process.stdout.write(text))
const final = await stream.finalMessage()
console.log('\n', final.usage)Prompt caching
Long prefixes you send every time, such as a system prompt or a product manual, can be marked with cache_control so the model caches them. Later requests that hit the cache pay the cache-read price for that part:
{
"model": "claude-sonnet-5-5",
"max_tokens": 1024,
"system": [
{ "type": "text", "text": "You are an after-sales agent. Answer only from the return policy below." },
{ "type": "text", "text": "(the full, long return policy goes here)", "cache_control": { "type": "ephemeral" } }
],
"messages": [{ "role": "user", "content": "Can I return an opened item?" }]
}cache_control is relayed to the model as-is. Cache writes and cache reads are each billed at their own price in the price list; check cache_read_input_tokens in the response usage to see whether you hit the cache. How caching works and when it pays off: What context caching is and how it saves money.
Notes
max_tokensis required. Put the system prompt in the top-levelsystem, not as a message inmessages.messagesmust start withuser, anduserandassistantmust alternate.- Extended thinking counts as output tokens; a larger
budget_tokensraises the most a single call can cost. - Claude groups differ in line source and price — see Choosing a group.
- To switch between vendors, use Chat Completions; Claude models the catalog lists for that endpoint work there too. For native features such as extended thinking and prompt caching, this endpoint is the more direct route.
Models that support this endpoint
| Model | Vendor | Cheapest group | Input ¥/1M | Output ¥/1M | Per request ¥ |
|---|---|---|---|---|---|
| Claude Haiku 5.5 | Anthropic | Claude Plus | ¥0.4 | ¥2 | — |
| Claude Sonnet 5.5 | Anthropic | Claude Lite | ¥3.2 | ¥16 | — |
| Claude Opus 5.5 | Anthropic | Claude Lite | ¥8 | ¥40 | — |
| claude-3-5-sonnet-all | Anthropic | Economy (per token) | — | — | ¥0.128 |
| Claude Haiku 5.5 | Anthropic | Claude Plus | ¥0.4 | ¥2 | — |
| claude-haiku-4-5-20251001-thinking | Anthropic | Claude Lite | ¥1.6 | ¥8 | — |
| claude-haiku-4-5-20251001 | Anthropic | Claude Lite | ¥1.6 | ¥8 | — |
| claude-3-haiku-20240307 | Anthropic | Claude Direct | ¥1.88 | ¥9.38 | — |
Prices in CNY, cheapest group for each model; updated Nov 12, 2026, 8:17 PM.
49 models support this endpoint; the table shows some of them. See them all in the model hub
Still stuck? Add our WeChat support JsnonoChat and send the request id from the error message, and we will look into it.