# Messages (/docs/api/messages)

`POST /v1/messages` speaks the Anthropic Messages protocol. Use it for Claude with the Anthropic SDKs and Claude Code, and for every other chat model in the catalog, which answers with the same content blocks. The full schema is in the [endpoint reference](/docs/api/chat/createMessage).

| | |
|---|---|
| Endpoint | `POST https://api.ohmygpt.com/v1/messages` |
| SDK base URL | `https://api.ohmygpt.com` |
| Auth | `x-api-key: $OHMYGPT_API_KEY` or `Authorization: Bearer $OHMYGPT_API_KEY` |

<Callout type="warn">
Set the base URL without `/v1`. The Anthropic SDKs and Claude Code append `/v1/messages` themselves, so `https://api.ohmygpt.com/v1` produces `/v1/v1/messages` and a 404.
</Callout>

```python tab="Python"
import os
from anthropic import Anthropic

client = Anthropic(
    base_url="https://api.ohmygpt.com",
    api_key=os.environ["OHMYGPT_API_KEY"],
)

message = client.messages.create(
    model="anthropic/claude-haiku-4-5",
    max_tokens=256,
    messages=[{"role": "user", "content": "Explain QUIC in two sentences."}],
)
print(message.content[0].text)
```

```bash tab="cURL"
curl https://api.ohmygpt.com/v1/messages \
  -H "x-api-key: $OHMYGPT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-haiku-4-5",
    "max_tokens": 256,
    "messages": [{"role": "user", "content": "Explain QUIC in two sentences."}]
  }'
```

You don't need to send `anthropic-version`; `2023-06-01` is added when it is missing. To use Claude Code, see [Claude Code](/docs/code-cli/claude-code).

## Claude [#claude]

Claude models receive your body and your `anthropic-*` headers, `anthropic-beta` included, as you sent them. Prompt caching, extended thinking, server tools, and beta features work as Anthropic documents them.

## Other models [#other-models]

Any other chat model also works here, with tools:

```bash
curl https://api.ohmygpt.com/v1/messages \
  -H "x-api-key: $OHMYGPT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ohmygpt/mock",
    "max_tokens": 64,
    "messages": [{"role": "user", "content": "What is the weather in Paris?"}],
    "tools": [{
      "name": "get_weather",
      "description": "Get weather",
      "input_schema": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
    }]
  }'
```

```json
{
  "type": "message",
  "role": "assistant",
  "model": "mock",
  "content": [
    { "type": "tool_use", "id": "call_mock_1", "name": "get_weather", "input": { "city": "" } }
  ],
  "stop_reason": "tool_use",
  "usage": { "input_tokens": 71, "output_tokens": 8 }
}
```

On these models:

- `stop_reason` is one of `end_turn`, `max_tokens`, `tool_use`, or `refusal`.
- `usage.output_tokens` includes the model's reasoning tokens.
- `anthropic-*` headers, `container`, `mcp_servers`, and server tools such as `web_search_20250305` are Claude features; use them with Claude models.
- `cache_control` is not sent. It changes what is cached, not the answer.

[Protocols](/docs/api/protocols#other-protocols) has the general rules.

## Counting tokens [#counting-tokens]

`POST /v1/messages/count_tokens` returns the input token count for a Claude request. It is free and does not create a usage record.

```bash
curl https://api.ohmygpt.com/v1/messages/count_tokens \
  -H "x-api-key: $OHMYGPT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "anthropic/claude-haiku-4-5", "messages": [{"role": "user", "content": "Hello, Claude"}]}'
```

```json
{ "input_tokens": 10 }
```

Use it with Claude models.

## Streaming [#streaming]

`stream: true` returns the Anthropic event sequence from `message_start` to `message_stop`, with `ping` events in between. A `: x-cost-credits` comment line comes right before `message_stop`. If the model fails after the stream has started, the stream ends with an `error` event. See [Streaming](/docs/api/streaming).
