> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.beatapi.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.beatapi.io/_mcp/server.

# Claude Messages

POST https://direct.beatapi.io/v1/messages
Content-Type: application/json

Call Claude Fable 5.1, Opus 5.5, Sonnet 5.5 and Haiku 5.5 through one Anthropic Messages endpoint with a BeatAPI key.- One endpoint, `POST /v1/messages`, for every current Claude model. Change `model` to switch.
- Text and image input, text output, streaming, tool use, extended thinking and prompt caching.
- Works with the Anthropic SDK: set the base URL to `https://direct.beatapi.io` (without `/v1`) and use a BeatAPI key.
- Claude models answer only on Anthropic Messages. A call to `/v1/responses` returns `400`.Use `https://direct.beatapi.io` as the base URL for text requests: it is not subject to Cloudflare's 100-second limit, so a long non-streaming request is not cut off. `https://api.beatapi.io` also works and is the fallback if `direct.beatapi.io` is unreachable from your network. The key, models and prices are the same on both. Image and video APIs use `https://api.beatapi.io` only.POST/v1/messagesTry itOpens this endpoint in the API Explorer. Enter your BeatAPI API key and send: the call is real and is billed to your own balance.## ModelsSend one of these IDs as `model`. Each is a separate model; do not treat them as aliases of each other.| Model ID            | Context (tokens) | Max output (tokens) | Positioning                                                                                                  | Input, USD per 1M tokens | Output, USD per 1M tokens | Notes                                                                                    |
| ------------------- | ---------------- | ------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------ | ------------------------- | ---------------------------------------------------------------------------------------- |
| `claude-opus-5-5`   | 1,000,000        | 128,000             | Claude Opus model for long-running agentic coding and knowledge work, priced below Opus 5                    | \$2.00                   | \$10.00                   | Long-running agentic coding and knowledge work.                                          |
| `claude-sonnet-5-5` | 1,000,000        | 128,000             | Claude Sonnet 5.5 for coding, reasoning, and professional work with a 1M-token context window.               | \$1.00                   | \$5.00                    | Everyday coding, reasoning and professional work.                                        |
| `claude-haiku-5-5`  | 1,000,000        | 128,000             | Fastest Claude model for high-volume, latency-sensitive work such as classification, extraction, and routing | \$0.05                   | \$0.25                    | The fastest Claude, for high-volume work such as classification, extraction and routing. |
| `claude-fable-5-1`  | 1,000,000        | 128,000             | Claude model for demanding reasoning and long-horizon agentic work                                           | \$5.00                   | \$25.00                   | Long-form writing and work where voice and structure matter most.                        |- Prices are the base tier, discount already applied. A long-context tier, cached-input rates and cache writes are not in this table; see the [price table](https://beatapi.io/pricing).
- `—` means the catalogue does not publish the number.Older IDs of this family still work and are listed on [Legacy models](/text-api/legacy-models).## Quick startInstall the `anthropic` package on your server, keep the key in `BEATAPI_API_KEY`, and never put it in browser code. These are request examples, not recorded model outputs.Read the answer from the `text` blocks in `content`, then check `stop_reason` and `usage`. An HTTP 200 alone does not prove the answer satisfies your task: validate it in your application. Text requests return directly; do not poll `/v1/tasks` for them.```bash title="cURL"
curl --request POST \
  --url https://direct.beatapi.io/v1/messages \
  --header "x-api-key: $BEATAPI_API_KEY" \
  --header 'anthropic-version: 2023-06-01' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "claude-sonnet-5-5",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    }
  ]
}'
``````python title="Python"
import os
from anthropic import Anthropic

client = Anthropic(api_key=os.environ["BEATAPI_API_KEY"], base_url="https://direct.beatapi.io")
message = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[
      {
        "role": "user",
        "content": "Design a resilient webhook retry strategy for a payments API."
      }
    ],
)
print(message.content[0].text)
``````javascript title="JavaScript"
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({ apiKey: process.env.BEATAPI_API_KEY, baseURL: "https://direct.beatapi.io" });
const message = await client.messages.create({
  "model": "claude-sonnet-5-5",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    }
  ]
});
console.log(message.content[0].text);
```## Endpoint and authentication`POST https://direct.beatapi.io/v1/messages`x-api-key
string
RequiredYour BeatAPI key. `Authorization: Bearer <BEATAPI_API_KEY>` is also accepted.Send the `anthropic-version` header, for example `anthropic-version: 2023-06-01`. The key goes in `x-api-key` or in `Authorization: Bearer <key>`; both work, so an existing Anthropic client only needs its base URL changed.Claude models answer only on Anthropic Messages. Calling one on `/v1/responses` returns `400`.## Request parametersStandard Anthropic Messages fields are accepted. Request-format compatibility does not mean every beta feature or server tool is supported, so test the options you rely on.model
string
RequiredThe exact model ID.**Allowed values**: `claude-fable-5-1`, `claude-opus-5-5`, `claude-sonnet-5-5`, `claude-haiku-5-5`- Older IDs that still work (`claude-opus-5`, `claude-sonnet-5`, `claude-haiku-4-5-20251001`) are on [Legacy models](/text-api/legacy-models).
- Call `GET /v1/models` with your key to confirm which models are enabled for it.max_tokens
integer
RequiredUpper bound on the generated tokens, thinking included.- Always send it. If it is missing or `0`, a default limit is applied, and that default may be lower than you expect.
- The largest accepted value is 1,073,741,823; a larger value is `400 bad_request`. Keep it at or below the max output of the model in the table above.
- `max_tokens` is also used to estimate how much balance a request needs. A very large value can be refused with `402 insufficient_credits` even when the real output would be small. Set it to what you need.messages
object[]
RequiredThe conversation, oldest message first. Each message has a `role` (`user` or `assistant`) and `content`. `content` is a string, or an array of content blocks.- Block types you will use: `text`, `image` (base64 or URL source), `tool_use` (in an assistant message), and `tool_result` (in a user message).
- An empty or missing `messages` array is `400 bad_request`.**Example**```json
[
  {
    "role": "user",
    "content": [
      { "type": "text", "text": "What is in this image?" },
      { "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": "<base64>" } }
    ]
  }
]
```system
string | object[]
OptionalSystem prompt. A string, or an array of `text` blocks. Put `cache_control` on a block to cache a long, stable prefix.**Example**```json
[
  {
    "type": "text",
    "text": "<long, stable instructions>",
    "cache_control": { "type": "ephemeral" }
  }
]
```stream
boolean
OptionalDefault: falseReturn the answer as server-sent events. See the Streaming section below.**Default**: `false`stop_sequences
string[]
OptionalCustom strings that stop generation. The response then has `stop_reason: "stop_sequence"`.tools
object[]
OptionalTools the model may call. Each has a `name`, a `description` and an `input_schema` (JSON Schema). When the model calls one, the answer has `stop_reason: "tool_use"`; run the tool and return the result in a following `tool_result` block.**Example**```json
[
  {
    "name": "get_weather",
    "description": "Get the current weather for a city.",
    "input_schema": {
      "type": "object",
      "properties": { "city": { "type": "string" } },
      "required": ["city"]
    }
  }
]
```tool_choice
object
OptionalWhether and how the model must use `tools`.**Allowed values**: `{"type":"auto"}`, `{"type":"any"}`, `{"type":"tool","name":"..."}`, `{"type":"none"}`- `auto` lets the model decide, `any` forces some tool, `tool` forces the named tool, `none` forbids tools.**Example**```json
{ "type": "auto" }
{ "type": "tool", "name": "get_weather" }
```thinking
object
OptionalExtended thinking. Set `type` to turn it on or off. Thinking tokens count toward `max_tokens` and are billed as output tokens.**Allowed values**: `adaptive`, `enabled`, `disabled`- `thinking.type` is one of the values above. `enabled` takes `thinking.budget_tokens` (an integer of at least 1,024, below `max_tokens`).
- `thinking.display` is `summarized` or `omitted`. Newer models may return no thinking text unless you ask for `summarized`.
- Set the depth of adaptive thinking with `output_config.effort`.**Per model**- `claude-fable-5-1`: Use `{"type":"adaptive"}` and set depth with `output_config.effort`; `budget_tokens` is rejected.
- `claude-opus-5-5`: Use `{"type":"adaptive"}` and set depth with `output_config.effort`; `budget_tokens` is rejected.
- `claude-sonnet-5-5`: Use `{"type":"adaptive"}` and set depth with `output_config.effort`; `budget_tokens` is rejected.**Example**```json
{
  "thinking": { "type": "adaptive" },
  "output_config": { "effort": "high" }
}
```output_config.effort
string
OptionalHow much reasoning the model does. Start with `high`, then evaluate one level lower and higher on your own workload.**Allowed values**: `low`, `medium`, `high`, `xhigh`, `max`cache_control
object
OptionalPrompt caching. Put it on a `system`, `messages` or `tools` block to cache everything up to that block, or at the top level of the request. `ttl` is `5m` (default) or `1h`.**Allowed values**: `{"type":"ephemeral"}`- Cache reads, 5-minute cache writes and 1-hour cache writes are metered separately; a cached prefix is charged as a cache read, not as fresh input.
- The cache hit counts are in `usage.cache_read_input_tokens` and `usage.cache_creation_input_tokens`.**Example**```json
{ "type": "ephemeral" }
{ "type": "ephemeral", "ttl": "1h" }
```## Tool use loopWhen `stop_reason` is `tool_use`, append the assistant message as it was returned, run the tool, and send the result in a `tool_result` block of the next `user` message. Send the same `tools` again.```json
{
  "max_tokens": 1024,
  "messages": [
    { "role": "user", "content": "What is the weather in Paris?" },
    {
      "role": "assistant",
      "content": [
        { "type": "tool_use", "id": "toolu_example", "name": "get_weather", "input": { "city": "Paris" } }
      ]
    },
    {
      "role": "user",
      "content": [
        { "type": "tool_result", "tool_use_id": "toolu_example", "content": "18 C, light rain" }
      ]
    }
  ]
}
```## ResponseA non-streaming call returns one JSON object. This is an abbreviated example.```json
{
  "id": "msg_example",
  "type": "message",
  "role": "assistant",
  "model": "claude-sonnet-5-5",
  "content": [
    {
      "type": "text",
      "text": "Retry with exponential backoff and jitter, and make every handler idempotent."
    }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 19,
    "output_tokens": 16
  }
}
```### Response fields| Field                               | Type      | Description                                                                                                                               |
| ----------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                                | `string`  | The message ID. Log it, together with the request ID, for support and billing audits.                                                     |
| `model`                             | `string`  | The model that answered.                                                                                                                  |
| `content[].type`                    | `string`  | `text`, `tool_use`, or `thinking` when thinking text is returned.                                                                         |
| `content[].text`                    | `string`  | The answer text of a `text` block.                                                                                                        |
| `stop_reason`                       | `string`  | `end_turn` for a complete answer, `max_tokens` when `max_tokens` was reached, `stop_sequence`, or `tool_use` when the model calls a tool. |
| `usage.input_tokens`                | `integer` | Input tokens that were not served from the cache.                                                                                         |
| `usage.output_tokens`               | `integer` | Output tokens, thinking included.                                                                                                         |
| `usage.cache_read_input_tokens`     | `integer` | Input tokens read from the prompt cache.                                                                                                  |
| `usage.cache_creation_input_tokens` | `integer` | Input tokens written to the prompt cache.                                                                                                 |## StreamingSet `"stream": true`. The response is a stream of Anthropic server-sent events, compatible with the Anthropic SDK.- The events are `message_start`, `ping`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta` and `message_stop`.
- Text arrives in `text_delta`, tool input in `input_json_delta` (concatenate the fragments, then parse), and thinking text in `thinking_delta`.
- `stop_reason` and the final output token count arrive in `message_delta`.
- The response is `text/event-stream`; without streaming it is `application/json`. A failure before the model is called is returned as a normal JSON error with an HTTP status, not as a stream event.
- Set explicit timeouts and reconnect a streamed response safely.```text
event: message_start
data: {"type":"message_start","message":{"id":"msg_example","type":"message","role":"assistant","model":"claude-sonnet-5-5","content":[],"stop_reason":null,"usage":{"input_tokens":19,"output_tokens":1}}}

event: ping
data: {"type":"ping"}

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

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

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

event: message_stop
data: {"type":"message_stop"}
```## Errors| Error or symptom                                                   | Cause                                                                                                         | Fix                                                                     |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `400`: missing `messages` or `model`, or `max_tokens` too large    | `messages` is empty or absent, `model` is empty, or `max_tokens` is above 1,073,741,823.                      | Send both fields and a `max_tokens` within the limit.                   |
| `400` on `/v1/responses`                                           | Claude models are not served on OpenAI Responses.                                                             | Call `POST /v1/messages`.                                               |
| `400` about a `thinking` setting                                   | The model does not accept that setting, for example `budget_tokens` on a model that uses adaptive thinking.   | Use the setting listed for the model under `thinking` above.            |
| `402 insufficient_credits`                                         | Balance below the price of the request, often because `max_tokens` is very large.                             | Top up, or lower `max_tokens`.                                          |
| `403 forbidden`                                                    | The account is on free credit and the model is not on the free list, or the model is outside the key's group. | Top up, use a free model, or use a key whose group can reach the model. |
| `404 not_found`                                                    | Unknown model ID, or not enabled for this key.                                                                | List the enabled models with `GET /v1/models`.                          |
| `429 rate_limit_exceeded`                                          | Account or free-model limit reached.                                                                          | Wait `Retry-After`, then retry.                                         |
| `200` with `stop_reason: "max_tokens"` and a short or empty answer | `max_tokens` was used up, often by thinking, before the answer was written.                                   | Raise `max_tokens`, or lower `output_config.effort`.                    |### HTTP errors at a glanceAuthentication, routing, rate-limit and unknown-model failures are answered before the model is called, in the BeatAPI envelope: `error.code`, `error.message`, `retryable`, `request_id`. Every other failure keeps the Anthropic shape `{"type": "error", "error": {"type", "message"}}`: the code is in `error.type` and the request id ends `message`. See [Errors](/errors#text-endpoints).| HTTP status | Code                                                       | What to do                                                                                   |
| ----------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| 400         | `bad_request`, `content_policy_violation`                  | Fix the request or the input; do not resend it unchanged.                                    |
| 401         | `missing_api_key`, `invalid_api_key`                       | Check the key. Do not retry.                                                                 |
| 402         | `insufficient_credits`                                     | Top up, or raise the key's limit. A very large `max_tokens` can trigger it.                  |
| 403         | `forbidden`                                                | The model is outside the key's group or IP allowlist, or free credit cannot call this model. |
| 404         | `not_found`                                                | Unknown model: list the enabled ones with `GET /v1/models`.                                  |
| 429         | `rate_limit_exceeded`                                      | Wait `Retry-After` or `retry_after_seconds`, then retry with backoff.                        |
| 500         | `internal_error`, `temporary_error`                        | Retry once or twice with backoff.                                                            |
| 503         | `model_unavailable`, `upstream_timeout`, `temporary_error` | Retry with backoff, or use another model.                                                    |Full code table and retry policy: [Errors](/errors#text-endpoints).## Notes- Claude models answer only on Anthropic Messages, not on [OpenAI Responses](/text-api/gpt/responses).
- Thinking tokens are billed as output tokens and count toward `max_tokens`. Budget enough output for thinking plus the answer.
- Keep API keys on trusted servers, log the response request ID, and retry only `429`, `500` and `503`.

Reference: https://docs.beatapi.io/api-reference/text-api/claude-messages

## Authentication

- `Authorization` header (bearer token, required) — Send your API key as `Authorization: Bearer <BEATAPI_API_KEY>`.

## Servers

- `https://direct.beatapi.io` (Direct, default)
- `https://api.beatapi.io` (API)

## Request

### Body (application/json)

This endpoint expects an object.

- `model` (enum, required) — The exact model ID. Older IDs that still work (`claude-opus-5`, `claude-sonnet-5`, `claude-haiku-4-5-20251001`) are on [Legacy models](/text-api/legacy-models). Call `GET /v1/models` with your key to confirm which models are enabled for it. `claude-fable-5-1`, `claude-opus-5-5`, `claude-sonnet-5-5`, `claude-haiku-5-5`
  - Allowed values: `claude-opus-5-5`, `claude-sonnet-5-5`, `claude-haiku-5-5`, `claude-fable-5-1`
- `max_tokens` (integer, required) — Upper bound on the generated tokens, thinking included. Always send it. If it is missing or `0`, a default limit is applied, and that default may be lower than you expect. The largest accepted value is 1,073,741,823; a larger value is `400 bad_request`. Keep it at or below the max output of the model in the table above. `max_tokens` is also used to estimate how much balance a request needs. A very large value can be refused with `402 insufficient_credits` even when the real output would be small. Set it to what you need.
- `messages` (list of V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItems, required) — The conversation, oldest message first. Each message has a `role` (`user` or `assistant`) and `content`. `content` is a string, or an array of content blocks. Block types you will use: `text`, `image` (base64 or URL source), `tool_use` (in an assistant message), and `tool_result` (in a user message). An empty or missing `messages` array is `400 bad_request`.
- `system` (V1MessagesPostRequestBodyContentApplicationJsonSchemaSystem, optional) — System prompt. A string, or an array of `text` blocks. Put `cache_control` on a block to cache a long, stable prefix.
- `stream` (boolean, optional, default: false) — Return the answer as server-sent events. See the Streaming section below.
- `stop_sequences` (list of string, optional) — Custom strings that stop generation. The response then has `stop_reason: "stop_sequence"`.
- `tools` (list of V1MessagesPostRequestBodyContentApplicationJsonSchemaToolsItems, optional) — Tools the model may call. Each has a `name`, a `description` and an `input_schema` (JSON Schema). When the model calls one, the answer has `stop_reason: "tool_use"`; run the tool and return the result in a following `tool_result` block.
- `tool_choice` (V1MessagesPostRequestBodyContentApplicationJsonSchemaToolChoice, optional) — Whether and how the model must use `tools`. `auto` lets the model decide, `any` forces some tool, `tool` forces the named tool, `none` forbids tools. `{"type":"auto"}`, `{"type":"any"}`, `{"type":"tool","name":"..."}`, `{"type":"none"}`
- `thinking` (V1MessagesPostRequestBodyContentApplicationJsonSchemaThinking, optional) — Extended thinking. Set `type` to turn it on or off. Thinking tokens count toward `max_tokens` and are billed as output tokens. `thinking.type` is one of the values above. `enabled` takes `thinking.budget_tokens` (an integer of at least 1,024, below `max_tokens`). `thinking.display` is `summarized` or `omitted`. Newer models may return no thinking text unless you ask for `summarized`. Set the depth of adaptive thinking with `output_config.effort`. `claude-fable-5-1`: Use `{"type":"adaptive"}` and set depth with `output_config.effort`; `budget_tokens` is rejected. `claude-opus-5-5`: Use `{"type":"adaptive"}` and set depth with `output_config.effort`; `budget_tokens` is rejected. `claude-sonnet-5-5`: Use `{"type":"adaptive"}` and set depth with `output_config.effort`; `budget_tokens` is rejected. `adaptive`, `enabled`, `disabled`
- `output_config` (V1MessagesPostRequestBodyContentApplicationJsonSchemaOutputConfig, optional)
- `cache_control` (V1MessagesPostRequestBodyContentApplicationJsonSchemaCacheControl, optional) — Prompt caching. Put it on a `system`, `messages` or `tools` block to cache everything up to that block, or at the top level of the request. `ttl` is `5m` (default) or `1h`. Cache reads, 5-minute cache writes and 1-hour cache writes are metered separately; a cached prefix is charged as a cache read, not as fresh input. The cache hit counts are in `usage.cache_read_input_tokens` and `usage.cache_creation_input_tokens`. `{"type":"ephemeral"}`

## Response

### 200

A non-streaming call returns one JSON object. This is an abbreviated example.

- `id` (string, optional) — The message ID. Log it, together with the request ID, for support and billing audits.
- `model` (string, optional) — The model that answered.
- `content` (list of V1MessagesPostResponsesContentApplicationJsonSchemaContentItems, optional)
- `stop_reason` (string, optional) — `end_turn` for a complete answer, `max_tokens` when `max_tokens` was reached, `stop_sequence`, or `tool_use` when the model calls a tool.
- `usage` (V1MessagesPostResponsesContentApplicationJsonSchemaUsage, optional)

## Errors

### 400 Bad Request Error

`bad_request`, `content_policy_violation` Fix the request or the input; do not resend it unchanged. Authentication, routing, rate-limit and unknown-model failures are answered before the model is called, in the BeatAPI envelope: `error.code`, `error.message`, `retryable`, `request_id`. Every other failure keeps the Anthropic shape `{"type": "error", "error": {"type", "message"}}`: the code is in `error.type` and the request id ends `message`. See [Errors](/errors#text-endpoints).

- `map from string to any`

### 401 Unauthorized Error

`missing_api_key`, `invalid_api_key` Check the key. Do not retry. Authentication, routing, rate-limit and unknown-model failures are answered before the model is called, in the BeatAPI envelope: `error.code`, `error.message`, `retryable`, `request_id`. Every other failure keeps the Anthropic shape `{"type": "error", "error": {"type", "message"}}`: the code is in `error.type` and the request id ends `message`. See [Errors](/errors#text-endpoints).

- `map from string to any`

### 402 Payment Required Error

`insufficient_credits` Top up, or raise the key's limit. A very large `max_tokens` can trigger it. Authentication, routing, rate-limit and unknown-model failures are answered before the model is called, in the BeatAPI envelope: `error.code`, `error.message`, `retryable`, `request_id`. Every other failure keeps the Anthropic shape `{"type": "error", "error": {"type", "message"}}`: the code is in `error.type` and the request id ends `message`. See [Errors](/errors#text-endpoints).

- `map from string to any`

### 403 Forbidden Error

`forbidden` The model is outside the key's group or IP allowlist, or free credit cannot call this model. Authentication, routing, rate-limit and unknown-model failures are answered before the model is called, in the BeatAPI envelope: `error.code`, `error.message`, `retryable`, `request_id`. Every other failure keeps the Anthropic shape `{"type": "error", "error": {"type", "message"}}`: the code is in `error.type` and the request id ends `message`. See [Errors](/errors#text-endpoints).

- `map from string to any`

### 404 Not Found Error

`not_found` Unknown model: list the enabled ones with `GET /v1/models`. Authentication, routing, rate-limit and unknown-model failures are answered before the model is called, in the BeatAPI envelope: `error.code`, `error.message`, `retryable`, `request_id`. Every other failure keeps the Anthropic shape `{"type": "error", "error": {"type", "message"}}`: the code is in `error.type` and the request id ends `message`. See [Errors](/errors#text-endpoints).

- `map from string to any`

### 429 Too Many Requests Error

`rate_limit_exceeded` Wait `Retry-After` or `retry_after_seconds`, then retry with backoff. Authentication, routing, rate-limit and unknown-model failures are answered before the model is called, in the BeatAPI envelope: `error.code`, `error.message`, `retryable`, `request_id`. Every other failure keeps the Anthropic shape `{"type": "error", "error": {"type", "message"}}`: the code is in `error.type` and the request id ends `message`. See [Errors](/errors#text-endpoints).

- `map from string to any`

### 500 Internal Server Error

`internal_error`, `temporary_error` Retry once or twice with backoff. Authentication, routing, rate-limit and unknown-model failures are answered before the model is called, in the BeatAPI envelope: `error.code`, `error.message`, `retryable`, `request_id`. Every other failure keeps the Anthropic shape `{"type": "error", "error": {"type", "message"}}`: the code is in `error.type` and the request id ends `message`. See [Errors](/errors#text-endpoints).

- `map from string to any`

### 503 Service Unavailable Error

`model_unavailable`, `upstream_timeout`, `temporary_error` Retry with backoff, or use another model. Authentication, routing, rate-limit and unknown-model failures are answered before the model is called, in the BeatAPI envelope: `error.code`, `error.message`, `retryable`, `request_id`. Every other failure keeps the Anthropic shape `{"type": "error", "error": {"type", "message"}}`: the code is in `error.type` and the request id ends `message`. See [Errors](/errors#text-endpoints).

- `map from string to any`

## Types

### V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItems

- `role` (string, required)
- `content` (V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContent, required)

### V1MessagesPostRequestBodyContentApplicationJsonSchemaSystem

System prompt. A string, or an array of `text` blocks. Put `cache_control` on a block to cache a long, stable prefix.

### V1MessagesPostRequestBodyContentApplicationJsonSchemaToolsItems

### V1MessagesPostRequestBodyContentApplicationJsonSchemaToolChoice

Whether and how the model must use `tools`. `auto` lets the model decide, `any` forces some tool, `tool` forces the named tool, `none` forbids tools. `{"type":"auto"}`, `{"type":"any"}`, `{"type":"tool","name":"..."}`, `{"type":"none"}`

### V1MessagesPostRequestBodyContentApplicationJsonSchemaThinking

Extended thinking. Set `type` to turn it on or off. Thinking tokens count toward `max_tokens` and are billed as output tokens. `thinking.type` is one of the values above. `enabled` takes `thinking.budget_tokens` (an integer of at least 1,024, below `max_tokens`). `thinking.display` is `summarized` or `omitted`. Newer models may return no thinking text unless you ask for `summarized`. Set the depth of adaptive thinking with `output_config.effort`. `claude-fable-5-1`: Use `{"type":"adaptive"}` and set depth with `output_config.effort`; `budget_tokens` is rejected. `claude-opus-5-5`: Use `{"type":"adaptive"}` and set depth with `output_config.effort`; `budget_tokens` is rejected. `claude-sonnet-5-5`: Use `{"type":"adaptive"}` and set depth with `output_config.effort`; `budget_tokens` is rejected. `adaptive`, `enabled`, `disabled`

- `type` (enum, optional)
  - Allowed values: `adaptive`, `enabled`, `disabled`

### V1MessagesPostRequestBodyContentApplicationJsonSchemaOutputConfig

- `effort` (enum, optional) — How much reasoning the model does. Start with `high`, then evaluate one level lower and higher on your own workload. `low`, `medium`, `high`, `xhigh`, `max`
  - Allowed values: `low`, `medium`, `high`, `xhigh`, `max`

### V1MessagesPostRequestBodyContentApplicationJsonSchemaCacheControl

Prompt caching. Put it on a `system`, `messages` or `tools` block to cache everything up to that block, or at the top level of the request. `ttl` is `5m` (default) or `1h`. Cache reads, 5-minute cache writes and 1-hour cache writes are metered separately; a cached prefix is charged as a cache read, not as fresh input. The cache hit counts are in `usage.cache_read_input_tokens` and `usage.cache_creation_input_tokens`. `{"type":"ephemeral"}`

### V1MessagesPostResponsesContentApplicationJsonSchemaContentItems

- `type` (string, optional) — `text`, `tool_use`, or `thinking` when thinking text is returned.
- `text` (string, optional) — The answer text of a `text` block.

### V1MessagesPostResponsesContentApplicationJsonSchemaUsage

- `input_tokens` (integer, optional) — Input tokens that were not served from the cache.
- `output_tokens` (integer, optional) — Output tokens, thinking included.
- `cache_read_input_tokens` (integer, optional) — Input tokens read from the prompt cache.
- `cache_creation_input_tokens` (integer, optional) — Input tokens written to the prompt cache.

### V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContent

## Examples

**Request**

```json
{
  "model": "claude-sonnet-5-5",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    }
  ]
}
```

**Response**

```json
{
  "id": "msg_example",
  "model": "claude-sonnet-5-5",
  "content": [
    {
      "type": "text",
      "text": "Retry with exponential backoff and jitter, and make every handler idempotent."
    }
  ],
  "stop_reason": "end_turn",
  "usage": {
    "input_tokens": 19,
    "output_tokens": 16
  },
  "role": "assistant",
  "stop_sequence": null,
  "type": "message"
}
```

**SDK Code**

```python Quick start
import requests

url = "https://direct.beatapi.io/v1/messages"

payload = {
    "model": "claude-sonnet-5-5",
    "max_tokens": 1024,
    "messages": [
        {
            "role": "user",
            "content": "Design a resilient webhook retry strategy for a payments API."
        }
    ]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Quick start
const url = 'https://direct.beatapi.io/v1/messages';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"model":"claude-sonnet-5-5","max_tokens":1024,"messages":[{"role":"user","content":"Design a resilient webhook retry strategy for a payments API."}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Quick start
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://direct.beatapi.io/v1/messages"

	payload := strings.NewReader("{\n  \"model\": \"claude-sonnet-5-5\",\n  \"max_tokens\": 1024,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Design a resilient webhook retry strategy for a payments API.\"\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Quick start
require 'uri'
require 'net/http'

url = URI("https://direct.beatapi.io/v1/messages")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"claude-sonnet-5-5\",\n  \"max_tokens\": 1024,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Design a resilient webhook retry strategy for a payments API.\"\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java Quick start
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://direct.beatapi.io/v1/messages")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"claude-sonnet-5-5\",\n  \"max_tokens\": 1024,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Design a resilient webhook retry strategy for a payments API.\"\n    }\n  ]\n}")
  .asString();
```

```php Quick start
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://direct.beatapi.io/v1/messages', [
  'body' => '{
  "model": "claude-sonnet-5-5",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Quick start
using RestSharp;

var client = new RestClient("https://direct.beatapi.io/v1/messages");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"claude-sonnet-5-5\",\n  \"max_tokens\": 1024,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Design a resilient webhook retry strategy for a payments API.\"\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Quick start
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "claude-sonnet-5-5",
  "max_tokens": 1024,
  "messages": [
    [
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    ]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://direct.beatapi.io/v1/messages")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```