# Messages

> Create a message with the Anthropic Messages API. This is the endpoint Claude Code uses.

**POST** `https://deference.si/v1/messages`

Follows Anthropic's Messages format. A successful response body passes through unchanged. Deference rebuilds error bodies in the Anthropic envelope. Provider errors that describe your request keep valid Anthropic types and wording. The request passes through except for two rewrites: a model id that is not the catalog id is replaced with that id, and a provider-run `web_search` tool's `max_uses` is capped to the request's tool-step allowance. A trailing `[1m]` is removed before the request is sent. Use `https://deference.si` as the SDK base URL, without `/v1`.

## Send a request

**curl**

```bash
curl https://deference.si/v1/messages \
  -H "x-api-key: $DEFERENCE_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-5.5",
    "max_tokens": 1024,
    "messages": [{ "role": "user", "content": "Say hello in one sentence." }]
  }'
```

**Python**

```python
import os
import anthropic

client = anthropic.Anthropic(base_url="https://deference.si", api_key=os.environ["DEFERENCE_API_KEY"])

message = client.messages.create(
    model="anthropic/claude-sonnet-5.5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Say hello in one sentence."}],
)
print(message.content[0].text)
```

**TypeScript**

```typescript
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  baseURL: "https://deference.si",
  apiKey: process.env.DEFERENCE_API_KEY,
});

const message = await client.messages.create({
  model: "anthropic/claude-sonnet-5.5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Say hello in one sentence." }],
});
console.log(message.content);
```

## Headers

* `x-api-key` (string, required): Your key. `Authorization: Bearer sk-df-...` works too.
* `anthropic-version` (string): Forwarded as sent. Anthropic's SDKs set it.
* `anthropic-beta` (string): Forwarded as sent. Any beta value is accepted.

## Request body

* `model` (string, required): The model id, such as `anthropic/claude-sonnet-5.5`.
* `max_tokens` (integer): The output limit. Required when the model lists no maximum output; without one the call returns `400 output_cap_required`. An explicit value is held in full up to the model's maximum. When omitted, the hold is the model's full maximum output, with no 32,768-token clamp. Deference does not send a cap of its own.
* `messages` (array, required): Alternating `user` and `assistant` turns. Content can be a string or an array of blocks.
* `system` (string | array): The system prompt. Send blocks to use `cache_control`.
* `stream` (boolean): Return server-sent events.
* `tools` (array): Tools the model may call.
* `tool_choice` (object): How the model picks a tool.
* `temperature` (number): Sampling temperature.
* `thinking` (object): Extended thinking settings, for models that support them.

A query string such as `?beta=true` is ignored.

## Credit held

Deference reserves credit for the prompt, the full `max_tokens` and allowed web-search steps. It never lowers `max_tokens` on Messages. A `web_search` tool's `max_uses` is capped to the request's tool-step allowance, which defaults to 30 and can be lowered with `max_tool_calls` — but not when `stop_server_tools_when` is set, which keeps the allowance at 30. Omitted or invalid `max_uses` uses that allowance.

A request whose hold does not fit in your available credit, or in its key's remaining limit, returns `402` with `billing_error`: lower `max_tokens` or add credit. A request that [free credit](https://deference.si/docs/concepts/free-credit) pays for runs on what it can hold. See [Pricing](https://deference.si/docs/concepts/pricing-and-metering).

## Files and URLs

* A model reads a PDF or other file itself only if it lists `file` input. For other models, the request returns `400 unsupported_parameter` unless it asks for the free parser: `"plugins": [{ "id": "file-parser", "pdf": { "engine": "cloudflare-ai" } }]`.
* Every file part, inline or given as a URL, and every image or video given as a URL is held at the larger of the text estimate and the model's context window, or 1,000,000 tokens when that window is unknown.
* A non-streamed call ends at 5 minutes when response headers have not arrived or the body stalls for that long, and otherwise at 15 minutes. It returns `504` with `error.type: timeout_error`. Nothing is charged yet, and the hold stays reserved, because the provider may still have run it. The OpenAI endpoints use `error.code: upstream_timeout`. A stream has no deadline of its own, but the same 5-minute header or body stalls end it. Before headers that costs zero. After headers, a reported cost is charged plus OpenRouter's 5% platform fee. Deference adds no markup. Stream long requests.

## Response

```json
{
  "id": "msg_01Ab3xQz9k",
  "type": "message",
  "role": "assistant",
  "model": "anthropic/claude-sonnet-5.5",
  "content": [{ "type": "text", "text": "Hello, nice to meet you." }],
  "stop_reason": "end_turn",
  "usage": { "input_tokens": 14, "output_tokens": 9 }
}
```

`usage` also reports `cache_creation_input_tokens` and `cache_read_input_tokens` when caching applies.

## Errors

Errors use Anthropic's envelope with `type: "error"` and Deference's `request_id`. The `x-request-id` and `request-id` headers carry the same id. See [Errors](https://deference.si/docs/api-reference/errors).
