> ## Documentation Index
> Fetch the complete documentation index at: https://tennda.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Native Claude Format

## Introduction

Claude's native message API, suitable for native Anthropic clients like Claude Code. This API follows Anthropic's specification and provides full Claude model capabilities, including Extended Thinking, tool calling, and other advanced features.

<Note>
  If you're using an OpenAI-compatible client (like OpenAI SDK), we recommend using the [`/v1/chat/completions`](/en/api-reference/endpoint/chat-openai) endpoint instead.
</Note>

## Authentication

<ParamField header="Authorization" type="string" required>
  Bearer Token, e.g., `Bearer sk-xxxxxxxxxx`
</ParamField>

## Request Parameters

<ParamField body="model" type="string" required>
  Claude model identifier, supported models include:

  * `claude-fable-5` - Claude Fable 5 (Latest, most capable)
  * `claude-opus-5` - Claude Opus 5 (Latest, complex agentic and coding work)
  * `claude-sonnet-5` - Claude Sonnet 5 (Best balance of speed and intelligence)
  * `claude-opus-4-8` - Claude Opus 4.8
  * `claude-opus-4-7` - Claude Opus 4.7
  * `claude-opus-4-6` - Claude Opus 4.6
  * `claude-sonnet-4-6` - Claude Sonnet 4.6 (Balanced performance)
  * `claude-opus-4-5-20251101` - Claude Opus 4.5
  * `claude-haiku-4-5-20251001` - Claude Haiku 4.5 (Fastest)
  * `claude-sonnet-4-5-20250929` - Claude Sonnet 4.5
  * `claude-sonnet-4-20250514` - Claude Sonnet 4
  * Other Claude series models
</ParamField>

<ParamField body="messages" type="array" required>
  List of conversation messages, each containing `role` (user/assistant) and `content`. `content` can be a string or an array of media content.
</ParamField>

<ParamField body="max_tokens" type="number" required>
  Maximum number of tokens to generate. Must be greater than 0.
</ParamField>

<ParamField body="system" type="string|array">
  System prompt, can be a string or an array of media content. Used to set the model's behavior and role.
</ParamField>

<ParamField body="temperature" type="number" default="1.0">
  Randomness control, 0-1. Higher values make responses more random. Recommended to set to 1.0 when using extended thinking.
</ParamField>

<ParamField body="top_p" type="number" default="1.0">
  Nucleus sampling parameter, 0-1, controls generation diversity. Recommended to set to 0 when using extended thinking.
</ParamField>

<ParamField body="top_k" type="number">
  Top-K sampling parameter, only supported by some models.
</ParamField>

<ParamField body="stream" type="boolean" default="false">
  Whether to enable streaming output, returns SSE format data chunks. Recommended to enable when using extended thinking.
</ParamField>

<ParamField body="stop_sequences" type="array">
  List of stop sequences. Generation stops when the model produces these sequences.
</ParamField>

<ParamField body="tools" type="array">
  Tool definitions list, supports function tools and web search tools.
</ParamField>

<ParamField body="tool_choice" type="object">
  Tool selection strategy, controls how the model uses tools.
</ParamField>

<ParamField body="thinking" type="object">
  Extended thinking configuration, enables Claude's deep reasoning capability.

  | Sub-field       | Type   | Description                                                                                                                                                                                                                                                         |
  | --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `type`          | enum   | `"adaptive"`: adaptive thinking — the model decides when and how deeply to think; `"disabled"`: turn thinking off. Claude 4.5 and earlier models use `"enabled"` together with `budget_tokens`                                                                      |
  | `display`       | enum   | `"summarized"`: return a summary of the thinking process; `"omitted"`: do not return thinking content. Thinking still happens and costs the same — `omitted` only hides it, and streaming reaches the reply text sooner. Cannot be combined with `type: "disabled"` |
  | `budget_tokens` | number | Only used with `type: "enabled"` (Claude 4.5 and earlier). Minimum 1024, and must be less than `max_tokens`; Claude 4.7 and newer models do not support this form                                                                                                   |

  ```json theme={null}
  {"type": "adaptive"}                            // adaptive thinking
  {"type": "adaptive", "display": "summarized"}   // adaptive thinking, return a thinking summary
  {"type": "disabled"}                            // thinking off
  ```

  **The default for `display` varies by model**: Claude Fable 5, Opus 5, Sonnet 5, Opus 4.8 and Opus 4.7 default to `"omitted"`; Claude Opus 4.6, Sonnet 4.6 and earlier default to `"summarized"`. To show the thinking process to users on the former, you **must explicitly set** `"display": "summarized"`, otherwise the thinking content comes back empty.
</ParamField>

<ParamField body="output_config" type="object">
  Output configuration, used to control the model's reasoning depth and token spend.

  | Sub-field | Type | Description                                                                                                                                                                                                                                                       |
  | --------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `effort`  | enum | Reasoning effort: `"low"` / `"medium"` / `"high"` / `"xhigh"` / `"max"`, defaults to `"high"`. Higher levels generally produce more accurate, more thorough answers but take longer and consume more tokens; try `"xhigh"` or `"max"` for coding and agentic work |

  ```json theme={null}
  {"effort": "high"}    // default level, identical to omitting the parameter
  {"effort": "xhigh"}   // coding / agentic long-horizon tasks
  ```

  This parameter affects **all** tokens in the response (reply text, tool calls, and thinking), so it takes effect even without thinking enabled.

  **Level availability varies by model**: `"xhigh"` is only supported on Claude Fable 5, Opus 5, Opus 4.8, Opus 4.7 and Sonnet 5; Claude Sonnet 4.5 and earlier models do not support this parameter at all.

  <Warning>
    On Claude Opus 5, thinking **cannot be disabled** at `"xhigh"` or `"max"` effort — combining those levels with `"thinking": {"type": "disabled"}` returns a 400 error. To disable thinking, set `effort` to `"high"` or lower.
  </Warning>
</ParamField>

<ParamField body="metadata" type="object">
  Request metadata for tracking and debugging.
</ParamField>

<ParamField body="mcp_servers" type="array">
  MCP (Model Context Protocol) server configuration.
</ParamField>

<ParamField body="context_management" type="object">
  Context management configuration, controls how conversation context is handled.
</ParamField>

## Prompt Caching

Prompt Caching allows you to cache frequently used context content, significantly reducing costs and improving response speed. Supports using the `cache_control` parameter in `system` and `messages`.

### Cache Control Parameters

<Warning>
  `cache_control` is **not a top-level request parameter** and cannot be placed at the root of the request body. It is a field marked on **content blocks**, and may only appear inside `system` array elements or `content` array elements in `messages`.
</Warning>

Fields:

| Field  | Description                                                                                                                                                                        |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | Cache type, always `"ephemeral"`                                                                                                                                                   |
| `ttl`  | Cache lifetime, optional. Omit for a 5-minute cache (default, most cost-effective); set to `"1h"` for a 1-hour cache (suitable for long-term stable context, but writes cost more) |

```json theme={null}
{"type": "ephemeral"}                  // 5-minute cache (default)
{"type": "ephemeral", "ttl": "1h"}     // 1-hour cache
```

Correct placement:

```json theme={null}
{
  "model": "claude-sonnet-4-5-20250929",
  "max_tokens": 1024,
  "system": [
    {
      "type": "text",
      "text": "Long, stable context...",
      "cache_control": {"type": "ephemeral"}
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Long document to cache...",
          "cache_control": {"type": "ephemeral", "ttl": "1h"}
        }
      ]
    }
  ]
}
```

### Caching Mechanism

* **Cache Breakpoints**: Up to **4 content blocks** can be marked per request. Each breakpoint writes its own cache entry covering the entire prefix from the beginning up to and including that block
* **Cache Hits**: The system compares the prefix at your breakpoint; if there is no match it walks backward one block at a time, with a lookback window of up to **20 content blocks**. Cache entries outside that window will not be hit — add an earlier breakpoint in that case
* **Cache Threshold**: Content shorter than the model's minimum cacheable length is not cached (no error is returned; it is simply processed as regular input). See the per-model table below
* **Cache Duration**: 5 minutes (default) or 1 hour
* **Cost**: Cache reads are **10%** of the regular input price (90% cheaper); cache writes carry a premium — **1.25x** for the 5-minute cache and **2x** for the 1-hour cache

#### Minimum Cacheable Length by Model

| Model                                                                  | Minimum Cacheable Length |
| ---------------------------------------------------------------------- | ------------------------ |
| Claude Fable 5, Claude Opus 5                                          | 512 tokens               |
| Claude Opus 4.8, Claude Sonnet 5, Claude Sonnet 4.6, Claude Sonnet 4.5 | 1,024 tokens             |
| Claude Opus 4.7                                                        | 2,048 tokens             |
| Claude Opus 4.6, Claude Opus 4.5, Claude Haiku 4.5                     | 4,096 tokens             |

### Use Cases

1. **Long Document Analysis**: Cache large documents in `system`, ask multiple questions
2. **Codebase Understanding**: Cache code context for multi-turn code analysis
3. **Knowledge Base Q\&A**: Cache knowledge base content for fast queries
4. **Multi-turn Conversations**: Cache conversation history to maintain context coherence

## Basic Examples

<Tabs>
  <Tab title="Non-streaming Request">
    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "messages": [
          {"role": "user", "content": "Please briefly introduce artificial intelligence"}
        ]
      }'
    ```
  </Tab>

  <Tab title="Streaming Request (SSE)">
    ```bash theme={null}
    curl -N -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "stream": true,
        "messages": [
          {"role": "user", "content": "Please briefly introduce artificial intelligence"}
        ]
      }'
    ```
  </Tab>

  <Tab title="Python Example (Anthropic SDK)">
    ```python theme={null}
    from anthropic import Anthropic

    client = Anthropic(
        api_key="sk-xxxxxxxxxx",
        base_url="https://api.tennda.ai"
    )

    # Non-streaming
    message = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[
            {"role": "user", "content": "Please briefly introduce artificial intelligence"}
        ]
    )
    print(message.content[0].text)

    # Streaming
    with client.messages.stream(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[
            {"role": "user", "content": "Please briefly introduce artificial intelligence"}
        ]
    ) as stream:
        for text_block in stream.text_stream:
            print(text_block, end="")
    ```
  </Tab>
</Tabs>

<ResponseExample>
  ```json theme={null}
  {
    "id": "msg_xxx",
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "text",
        "text": "Artificial intelligence is a branch of computer science that focuses on creating intelligent machines capable of performing tasks that typically require human intelligence..."
      }
    ],
    "model": "claude-sonnet-4-5-20250929",
    "stop_reason": "end_turn",
    "stop_sequence": null,
    "usage": {
      "input_tokens": 25,
      "output_tokens": 100
    }
  }
  ```
</ResponseExample>

## Advanced Features

### System Prompt

System prompts can be set as a string or an array of media content:

<Tabs>
  <Tab title="String Format">
    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "system": "You are a helpful assistant that excels at answering questions.",
        "messages": [
          {"role": "user", "content": "What is machine learning?"}
        ]
      }'
    ```
  </Tab>

  <Tab title="Array Format">
    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "system": [
          {"type": "text", "text": "You are a helpful assistant that excels at answering questions."}
        ],
        "messages": [
          {"role": "user", "content": "What is machine learning?"}
        ]
      }'
    ```
  </Tab>
</Tabs>

### Extended Thinking

Claude supports extended thinking, allowing the model to perform deep reasoning. When enabled, the model will think internally before generating the final answer.

<Tabs>
  <Tab title="Basic Usage">
    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 4096,
        "temperature": 1.0,
        "top_p": 0,
        "stream": true,
        "messages": [
          {"role": "user", "content": "Give a medium difficulty geometry problem and solve it step by step"}
        ]
      }'
    ```
  </Tab>

  <Tab title="Python Example">
    ```python theme={null}
    from anthropic import Anthropic

    client = Anthropic(
        api_key="sk-xxxxxxxxxx",
        base_url="https://api.tennda.ai"
    )

    with client.messages.stream(
        model="claude-sonnet-4-5-20250929",
        max_tokens=4096,
        thinking={
            "type": "enabled",
            "budget_tokens": 4096
        },
        temperature=1.0,
        top_p=0,
        messages=[
            {"role": "user", "content": "Give a medium difficulty geometry problem and solve it step by step"}
        ]
    ) as stream:
        for event in stream:
            if event.type == "content_block_delta":
                if hasattr(event.delta, "thinking"):
                    # Thinking process
                    print(f"[Thinking] {event.delta.thinking}", end="")
                elif hasattr(event.delta, "text"):
                    # Final answer
                    print(event.delta.text, end="")
    ```
  </Tab>
</Tabs>

<Note>
  * `budget_tokens` must be greater than 1024
  * When using extended thinking, it's recommended to set `temperature: 1.0` and `top_p: 0`
  * Streaming output (`stream: true`) must be enabled to see the thinking process
</Note>

### Tool Calling

Supports function tools and web search tools:

<Tabs>
  <Tab title="Function Tools">
    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "tools": [
          {
            "name": "get_weather",
            "description": "Get weather information for a city",
            "input_schema": {
              "type": "object",
              "properties": {
                "city": {
                  "type": "string",
                  "description": "City name"
                }
              },
              "required": ["city"]
            }
          }
        ],
        "tool_choice": {
          "type": "auto"
        },
        "messages": [
          {"role": "user", "content": "What is the weather in Shanghai?"}
        ]
      }'
    ```
  </Tab>

  <Tab title="Claude Official Web Search Tool">
    Claude supports the official web search tool `web_search_20250305`, which can search the web in real-time and include citation sources in responses.

    <Note>Note: AWS Bedrock does not support this search tool</Note>

    **Basic Usage**:

    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "tools": [
          {
            "type": "web_search_20250305",
            "name": "web_search"
          }
        ],
        "messages": [
          {"role": "user", "content": "What are the latest news about artificial intelligence?"}
        ]
      }'
    ```

    **With Search Limit**:

    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "tools": [
          {
            "type": "web_search_20250305",
            "name": "web_search",
            "max_uses": 5
          }
        ],
        "messages": [
          {"role": "user", "content": "Search for today'\''s weather in Beijing"}
        ]
      }'
    ```

    **With Location Information (Improves Search Accuracy)**:

    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "tools": [
          {
            "type": "web_search_20250305",
            "name": "web_search",
            "max_uses": 5,
            "user_location": {
              "type": "approximate",
              "timezone": "Asia/Shanghai",
              "country": "CN",
              "region": "Beijing",
              "city": "Beijing"
            }
          }
        ],
        "messages": [
          {"role": "user", "content": "What'\''s the weather in Shanghai today?"}
        ]
      }'
    ```

    **Python Example**:

    ```python theme={null}
    from anthropic import Anthropic

    client = Anthropic(
        api_key="sk-xxxxxxxxxx",
        base_url="https://api.tennda.ai"
    )

    message = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        tools=[
            {
                "type": "web_search_20250305",
                "name": "web_search",
                "max_uses": 5
            }
        ],
        messages=[
            {"role": "user", "content": "What are the latest news about artificial intelligence?"}
        ]
    )
    print(message.content[0].text)
    ```

    <Note>
      * `type` must be `"web_search_20250305"`
      * `name` must be `"web_search"`
      * `max_uses` (optional): Maximum number of search uses in a single conversation, recommended value: 2-10
      * `user_location` (optional): User location information to improve localization accuracy of search results
      * Search results will automatically include citation sources in the response
      * Supported models include Claude Sonnet 4.5, Claude Opus 4.5, Claude Haiku 4.5, etc.
    </Note>
  </Tab>

  <Tab title="Complete Tool Calling Flow">
    Phase 1: Model returns tool call request

    ```json theme={null}
    {
      "id": "msg_xxx",
      "content": [
        {
          "type": "tool_use",
          "id": "toolu_xxx",
          "name": "get_weather",
          "input": {"city": "Shanghai"}
        }
      ],
      "stop_reason": "tool_use"
    }
    ```

    Phase 2: Return tool execution result

    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "tools": [...],
        "messages": [
          {"role": "user", "content": "What is the weather in Shanghai?"},
          {
            "role": "assistant",
            "content": [
              {
                "type": "tool_use",
                "id": "toolu_xxx",
                "name": "get_weather",
                "input": {"city": "Shanghai"}
              }
            ]
          },
          {
            "role": "user",
            "content": [
              {
                "type": "tool_result",
                "tool_use_id": "toolu_xxx",
                "content": "{\"temp\":\"22°C\",\"condition\":\"Cloudy\",\"aqi\":53}"
              }
            ]
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

### tool\_choice Parameter Details

`tool_choice` controls how the model uses tools:

| Value                                   | Description                                         |
| --------------------------------------- | --------------------------------------------------- |
| `{"type": "auto"}`                      | Automatically decide whether to use tools (default) |
| `{"type": "any"}`                       | Must use at least one tool                          |
| `{"type": "none"}`                      | Don't use any tools                                 |
| `{"type": "tool", "name": "tool_name"}` | Must use the specified tool                         |

Example:

```json theme={null}
{
  "tool_choice": {
    "type": "auto",
    "disable_parallel_tool_use": false
  }
}
```

### Multimodal Input (Images)

Supports including images in messages:

```bash theme={null}
curl -X POST "https://api.tennda.ai/v1/messages" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-xxxxxxxxxx" \
  -d '{
    "model": "claude-sonnet-4-5-20250929",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "image",
            "source": {
              "type": "base64",
              "media_type": "image/png",
              "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
            }
          },
          {
            "type": "text",
            "text": "What is in this image?"
          }
        ]
      }
    ]
  }'
```

### Prompt Caching

Caching frequently used context content can significantly reduce costs and improve response speed.

<Tabs>
  <Tab title="System Cache (5 minutes)">
    ```bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "system": [
          {
            "type": "text",
            "text": "You are a professional technical documentation analyst. Here is the complete AWS Lambda technical documentation:\n\nAWS Lambda is a serverless computing service...[large documentation content, at least 1024 tokens]",
            "cache_control": {"type": "ephemeral"}
          }
        ],
        "messages": [
          {"role": "user", "content": "What is Lambda's pricing model?"}
        ]
      }'
    ```

    **First Request Response**:

    ```json theme={null}
    {
      "usage": {
        "input_tokens": 50,
        "cache_creation_input_tokens": 1200,
        "cache_read_input_tokens": 0,
        "output_tokens": 150
      }
    }
    ```

    **Second Request within 5 minutes (different question, same system)**:

    ```json theme={null}
    {
      "usage": {
        "input_tokens": 45,
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 1200,
        "output_tokens": 100
      }
    }
    ```
  </Tab>

  <Tab title="Messages Cache (1 hour)">
    ````bash theme={null}
    curl -X POST "https://api.tennda.ai/v1/messages" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk-xxxxxxxxxx" \
      -d '{
        "model": "claude-sonnet-4-5-20250929",
        "max_tokens": 1024,
        "system": "You are a Python programming assistant",
        "messages": [
          {
            "role": "user",
            "content": [
              {
                "type": "text",
                "text": "Analyze this code:\n```python\n[large code snippet, at least 1024 tokens]\n```",
                "cache_control": {"type": "ephemeral", "ttl": "1h"}
              }
            ]
          },
          {
            "role": "assistant",
            "content": [
              {
                "type": "text",
                "text": "The main functionality of this code is...[detailed analysis]",
                "cache_control": {"type": "ephemeral", "ttl": "1h"}
              }
            ]
          },
          {
            "role": "user",
            "content": "How can I optimize the performance of this code?"
          }
        ]
      }'
    ````

    **Advantages of the 1-hour cache (`ttl: "1h"`)**:

    * 1-hour cache duration, suitable for long sessions
    * Ideal for code reviews, document analysis, etc.
    * Faster subsequent requests after cache hit
  </Tab>

  <Tab title="Python SDK Example">
    ```python theme={null}
    from anthropic import Anthropic

    client = Anthropic(
        api_key="sk-xxxxxxxxxx",
        base_url="https://api.tennda.ai"
    )

    # First request: Create cache
    message1 = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        system=[
            {
                "type": "text",
                "text": "You are a professional document analyst...[long text content]",
                "cache_control": {"type": "ephemeral"}
            }
        ],
        messages=[
            {"role": "user", "content": "First question"}
        ]
    )

    print(f"Cache created: {message1.usage.cache_creation_input_tokens} tokens")
    print(f"Cache read: {message1.usage.cache_read_input_tokens} tokens")

    # Second request within 5 minutes: Use cache
    message2 = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        system=[
            {
                "type": "text",
                "text": "You are a professional document analyst...[same long text]",
                "cache_control": {"type": "ephemeral"}
            }
        ],
        messages=[
            {"role": "user", "content": "Second question"}
        ]
    )

    print(f"Cache created: {message2.usage.cache_creation_input_tokens} tokens")
    print(f"Cache read: {message2.usage.cache_read_input_tokens} tokens")
    ```
  </Tab>
</Tabs>

<Note>
  **Cache Key Points**:

  * Content must meet the model's minimum cacheable length to trigger caching (512–4,096 tokens depending on the model — see the table above)
  * Without `ttl`, the cache is valid for **5 minutes**
  * With `ttl: "1h"`, the cache is valid for **1 hour**
  * Cache reads cost **90% less** than regular inputs; cache writes carry a premium (1.25x for 5 minutes, 2x for 1 hour)
  * Up to **4 blocks** can be marked per request, and each breakpoint writes its own cache entry
  * Cache is based on exact content match; any changes invalidate the cache
</Note>

<Tip>
  **Best Practices**:

  * Place unchanging long context (documents, codebases, etc.) in `system` with caching enabled
  * Use the 1-hour cache (`ttl: "1h"`) for long-term stable content
  * Use the default 5-minute cache (omit `ttl`) for frequently changing content
  * Cache conversation history in multi-turn dialogues
  * Monitor `cache_creation_input_tokens` and `cache_read_input_tokens` to optimize costs
</Tip>

## Response Format

<Tabs>
  <Tab title="Non-streaming Response">
    ```json theme={null}
    {
      "id": "msg_xxx",
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "text",
          "text": "Response content..."
        }
      ],
      "model": "claude-sonnet-4-5-20250929",
      "stop_reason": "end_turn",
      "stop_sequence": null,
      "usage": {
        "input_tokens": 25,
        "cache_creation_input_tokens": 0,
        "cache_read_input_tokens": 0,
        "output_tokens": 100
      }
    }
    ```

    **Usage fields when using cache**:

    * `input_tokens`: Non-cached input tokens for the current request
    * `cache_creation_input_tokens`: Tokens cached for the first time (only present in first request)
    * `cache_read_input_tokens`: Tokens read from cache (present when cache hits)
    * `output_tokens`: Generated output tokens
  </Tab>

  <Tab title="Streaming Response">
    Streaming responses are returned in SSE (Server-Sent Events) format, containing the following event types:

    * `message_start`: Message start
    * `content_block_start`: Content block start
    * `content_block_delta`: Content delta (contains `text` or `thinking`)
    * `content_block_stop`: Content block end
    * `message_delta`: Message delta (contains usage info)
    * `message_stop`: Message end

    ```json theme={null}
    event: message_start
    data: {"type":"message_start","message":{"id":"msg_xxx","type":"message","role":"assistant","content":[],"model":"claude-sonnet-4-5-20250929","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":25,"output_tokens":0}}}

    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":"Response"}}

    event: content_block_delta
    data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" content"}}

    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":100}}

    event: message_stop
    data: {"type":"message_stop"}
    ```

    When using extended thinking, `content_block_delta` may contain a `thinking` field:

    ```json theme={null}
    event: content_block_delta
    data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"Let me think about this problem..."}}
    ```
  </Tab>
</Tabs>

## Error Handling

The system processes upstream Claude API errors and returns standardized error response formats.

| Error Type             | HTTP Status Code | Description                                             |
| ---------------------- | ---------------- | ------------------------------------------------------- |
| `invalid_request`      | 400              | Request parameter error (e.g., missing required fields) |
| `authentication_error` | 401              | Invalid or unauthorized API key                         |
| `rate_limit_error`     | 429              | Request rate limit exceeded                             |
| `upstream_error`       | 500              | Upstream service error                                  |
| `tennda_api_error`     | 500              | System internal error                                   |

Error response example:

```json theme={null}
{
  "error": {
    "type": "invalid_request",
    "message": "field messages is required"
  }
}
```

## Comparison with /v1/chat/completions

| Feature           | /v1/messages                     | /v1/chat/completions                            |
| ----------------- | -------------------------------- | ----------------------------------------------- |
| Authentication    | `Authorization: Bearer`          | `Authorization: Bearer`                         |
| Response Format   | Anthropic native format          | OpenAI compatible format                        |
| Extended Thinking | Native `thinking` parameter      | Via `reasoning_effort` or `reasoning` parameter |
| Tool Calling      | Native `tools` and `tool_choice` | OpenAI compatible format                        |
| Suitable Clients  | Anthropic SDK, Claude Code       | OpenAI SDK, compatible clients                  |

<Tip>
  * If you're using Claude Code or other Anthropic native clients, we recommend using the `/v1/messages` endpoint
  * If you're using OpenAI SDK or need OpenAI format compatibility, we recommend using the `/v1/chat/completions` endpoint
  * Both endpoints have essentially the same functionality, the main difference is in request/response format
</Tip>

## Notes

<Note>
  * `max_tokens` is a required parameter and must be greater than 0
  * `messages` array cannot be empty
  * When using extended thinking, `budget_tokens` must be greater than 1024
  * Extended thinking requires streaming output to see the thinking process
  * Tool calling requires multiple rounds of interaction: first round returns tool call request, second round returns tool execution result
  * Image input requires base64 encoding
</Note>

<Tip>
  * Using streaming output can improve first token response time and interaction experience
  * Tool calling should have proper timeout and retry mechanisms to avoid blocking model responses
  * Extended thinking can significantly improve reasoning quality for complex problems
</Tip>

## Related Resources

<Columns cols={2}>
  <Card title="Chat Completions (OpenAI Compatible)" icon="message" href="/en/api-reference/endpoint/chat-openai">
    View OpenAI compatible chat endpoint documentation
  </Card>

  <Card title="Model List" icon="list" href="/en/api-reference/models">
    View all supported model information
  </Card>
</Columns>
