# Messages

Generate a model response using the Anthropic Messages wire format. Use this endpoint with the Anthropic SDKs, Claude Code and any tool that has an "Anthropic base URL" setting; it serves the same Claudech models and bills identically to [Chat completions](https://claudech.com/docs/api/chat-completions).

**`POST /v1/messages`**

> **Note**
>
> Claudech is an independent service. This endpoint implements a request format for interoperability; it is not affiliated with Anthropic and every request is served by a Claudech model.

## Authentication

Send your key as `x-api-key: sk-...` (what the Anthropic SDKs do) or `Authorization: Bearer sk-...`. The `anthropic-version` header is accepted and ignored.

## Request body

- `model` (string, required): A Claudech model slug or alias, for example `claude-opus-5-5`.
- `max_tokens` (integer, required): Upper bound on generated tokens, including thinking tokens.
- `messages` (array, required): Alternating `user` / `assistant` turns. `content` is a string or an array of blocks: `text`, `image` (`source.type` = `base64` or `url`), `tool_use` (assistant), `tool_result` (user) and `thinking`. Unknown block types are ignored.
- `system` (string | array): System prompt, either a string or an array of `text` blocks. `cache_control` markers are accepted and ignored.
- `temperature` (number): Between `0` and `1`.
- `top_p` (number): Nucleus sampling threshold in `(0, 1]`.
- `top_k` (integer): Accepted for compatibility; not applied.
- `stop_sequences` (string[]): Up to 16 sequences at which generation halts.
- `stream` (boolean, default `false`): Stream the response as server-sent events (see below).
- `tools` (array): Tool definitions: `{ name, description?, input_schema }`. Up to 128.
- `tool_choice` (object): `{ type: "auto" }`, `{ type: "any" }`, `{ type: "none" }` or `{ type: "tool", name }`.
- `thinking` (object): `{ type: "enabled", budget_tokens? }` turns on reasoning for reasoning-capable models; `{ type: "disabled" }` turns it off. `budget_tokens` is accepted but the model's own limits apply.
- `metadata` (object): `{ user_id }` is recorded on usage records for your own attribution.

## Response

```json
{
  "id": "msg_01J9X3Q5K7M2N8P4R6T0V2W4Y6",
  "type": "message",
  "role": "assistant",
  "model": "claude-opus-5-5",
  "content": [{ "type": "text", "text": "Rivers carve the stone..." }],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 18,
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 0,
    "output_tokens": 42,
    "claud_tokens_debited": "102",
    "claud_cost_usd": "0.000204"
  }
}
```

- `content` (array): Ordered blocks: `thinking` (reasoning models with thinking enabled), `text`, and `tool_use` (`{ id, name, input }` with `input` already parsed as an object).
- `stop_reason` (string): `end_turn`, `max_tokens` or `tool_use`. Claudech cannot distinguish a stop sequence from a natural end, so `stop_sequence` is always `null` and such stops report `end_turn`.
- `usage.input_tokens` (integer): Prompt tokens that were not served from cache. `cache_read_input_tokens` holds the cached portion; the two sum to the total prompt size.
- `usage.output_tokens` (integer): Generated tokens, including thinking tokens.
- `usage.claud_tokens_debited` (string): Claudech tokens charged for this request.
- `usage.claud_cost_usd` (string): The same charge in USD.

The response also carries the `x-request-id`, `x-claud-model`, `x-claud-tokens-debited`, `x-claud-balance` and `x-ratelimit-*` headers described under [Chat completions](https://claudech.com/docs/api/chat-completions#response-headers).

## Streaming

With `"stream": true` the response is a `text/event-stream` in the Messages event sequence:

```text
event: message_start
data: {"type":"message_start","message":{"id":"msg_...","type":"message","role":"assistant","model":"claude-opus-5-5","content":[],"stop_reason":null,"usage":{"input_tokens":0,"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":"Rivers "}}

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":{"input_tokens":18,"cache_read_input_tokens":0,"output_tokens":42,"claud_tokens_debited":"102","claud_cost_usd":"0.000204","claud_balance_tokens":"1199400","claud_fallback_used":false}}

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

- Thinking arrives as a `thinking` block with `thinking_delta` deltas, before the text block.
- Tool calls arrive as `tool_use` blocks: `content_block_start` carries `id` and `name`; `input_json_delta` deltas carry `partial_json` fragments that concatenate to the arguments object.
- Final token counts and billing are on `message_delta`. `claud_balance_tokens` is your available balance after the request; `claud_fallback_used` is `true` if a fallback model served it.
- Errors after the stream has started are sent as `event: error` with an Anthropic-style error body, followed by the end of the stream.

## Count tokens

**`POST /v1/messages/count_tokens`**

Accepts the same body as `/v1/messages` (`max_tokens` optional) and returns `{ "input_tokens": n }` using the same estimator the gateway uses to reserve tokens before a request. Not billed and not rate limited against your token budget.

## Examples

**curl**

```bash
curl https://api.claudech.com/v1/messages \
  -H "x-api-key: $CLAUDECH_API_KEY" \
  -H "anthropic-version: 2026-11-08" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-5-5",
    "max_tokens": 200,
    "system": "You are a concise assistant.",
    "messages": [{"role": "user", "content": "Write a haiku about rivers."}]
  }'
```

**JavaScript**

```javascript
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.CLAUDECH_API_KEY, baseURL: 'https://api.claudech.com' });

const msg = await client.messages.create({
  model: 'claude-opus-5-5',
  max_tokens: 200,
  system: 'You are a concise assistant.',
  messages: [{ role: 'user', content: 'Write a haiku about rivers.' }],
});
console.log(msg.content[0].text);
```

**Python**

```python
from anthropic import Anthropic
client = Anthropic(api_key=os.environ["CLAUDECH_API_KEY"], base_url="https://api.claudech.com")

msg = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=200,
    system="You are a concise assistant.",
    messages=[{"role": "user", "content": "Write a haiku about rivers."}],
)
print(msg.content[0].text)
```

### Tool use round trip

```json
{
  "model": "claude-opus-5-5",
  "max_tokens": 400,
  "tools": [{
    "name": "get_weather",
    "description": "Current weather for a city",
    "input_schema": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] }
  }],
  "messages": [
    { "role": "user", "content": "What is the weather in Paris?" },
    { "role": "assistant", "content": [
      { "type": "tool_use", "id": "toolu_01", "name": "get_weather", "input": { "city": "Paris" } }
    ]},
    { "role": "user", "content": [
      { "type": "tool_result", "tool_use_id": "toolu_01", "content": "18°C, cloudy" }
    ]}
  ]
}
```

## Errors

Errors use the Messages envelope `{ "type": "error", "error": { "type", "message", "code", "request_id" } }`. Codes are the same as for [Chat completions](https://claudech.com/docs/api/chat-completions#errors); `error.type` is one of `invalid_request_error`, `authentication_error`, `permission_error`, `not_found_error`, `rate_limit_error`, `request_too_large`, `overloaded_error` or `api_error`.

---

Source: https://claudech.com/docs/api/messages
