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

# Messages (Anthropic format)

> Send a conversation in the Anthropic Messages format and get an Anthropic-shaped reply from any Kyma chat model.

Use this endpoint when your client speaks the Anthropic Messages API (the Anthropic SDKs, Claude Code, and agents built on them). Point the SDK's base URL at `https://kymaapi.com` and it calls this path itself. Setup per SDK: [Anthropic SDK guide](/guides/anthropic).

## Authentication

Send your key as `x-api-key: kyma-...` (what the Anthropic SDKs send) or as `Authorization: Bearer kyma-...`. Either works.

## Request body

<ParamField body="model" type="string" required>
  A Kyma model id or alias, for example `deepseek-v4-flash`. Any chat model works; see [`GET /v1/models`](/api-reference/models-list). This endpoint returns `400` naming the endpoint to use for an embedding model ([`POST /v1/embeddings`](/api-reference/embeddings)), a reranking model ([`POST /v1/rerank`](/api-reference/rerank)), a decisions model (`POST /v1/decisions`), a model that does not produce text (for example image or speech) and a model that does not take text (transcription, audio understanding).
</ParamField>

<ParamField body="messages" type="array" required>
  The conversation, as `{role, content}` objects with `role` `"user"` or `"assistant"`. `content` is a string or an array of blocks:

  * `text`
  * `image`, with a `base64` source (plus `media_type`) or a `url` source, on a model that accepts images (`GET /v1/models?input_modalities=image`). Other image sources, and images sent to a text-only model, return `400`.
  * `document`, with a `text` source only. PDF, url, file and custom-content documents return `400`: send the text instead.
  * `tool_use` (assistant turns) and `tool_result` (user turns). A `tool_result` may hold a string or `text`, `document` and `image` blocks.

  Other block types are not forwarded to the model.
</ParamField>

<ParamField body="system" type="string | array">
  The system prompt, as a string or an array of `text` blocks. `cache_control` on a system block is kept. See [Prompt caching](/guides/prompt-caching).
</ParamField>

<ParamField body="max_tokens" type="integer" default="4096">
  Maximum tokens to generate. Unlike Anthropic's API, it is optional here: when omitted, Kyma sends `4096`. If your balance cannot pay for all of them, Kyma lowers the value and says so in the `x-kyma-max-tokens-clamped` header.
</ParamField>

<ParamField body="stream" type="boolean" default="false">
  Stream the reply as Anthropic server-sent events.
</ParamField>

<ParamField body="temperature" type="number">
  Sampling temperature. When omitted, the model's own default applies.
</ParamField>

<ParamField body="top_p" type="number">
  Nucleus sampling. When omitted, the model's own default applies.
</ParamField>

<ParamField body="stop_sequences" type="array">
  Strings that end generation.
</ParamField>

<ParamField body="tools" type="array">
  Tool definitions: `name`, `description`, `input_schema` (JSON Schema). On models with `supports_tools: true`. See [Tool calling](/guides/tool-calling).
</ParamField>

<ParamField body="tool_choice" type="object">
  `{"type": "auto"}`, `{"type": "any"}`, `{"type": "none"}` or `{"type": "tool", "name": "..."}`, with optional `disable_parallel_tool_use: true`. `none` and `disable_parallel_tool_use` are applied only when `tools` is also sent.
</ParamField>

Other fields, such as `top_k`, `thinking` and `metadata`, are not forwarded to the model.

## Response

```json theme={null}
{
  "id": "msg_abc123",
  "type": "message",
  "role": "assistant",
  "content": [
    { "type": "text", "text": "Hello! How can I help you today?" }
  ],
  "model": "deepseek-v4-flash",
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": { "input_tokens": 12, "output_tokens": 10 }
}
```

* `content` holds a `text` block, then one `tool_use` block (`id`, `name`, `input`) per tool call.
* `stop_reason` is `end_turn`, `max_tokens` or `tool_use`. `stop_sequence` is always `null`.
* `model` is the Kyma id your request resolved to.
* `usage` carries `input_tokens` and `output_tokens` only.

With `stream: true` you get the Anthropic event sequence: `message_start`, `content_block_start`, `content_block_delta` (`text_delta`, or `input_json_delta` for tool input), `content_block_stop`, `message_delta`, `message_stop`. Kyma does not send an `error` event on this stream today.

## Response headers

| Header | When |
| - | - |
| `x-kyma-model` | Always. The model id your request resolved to |
| `x-kyma-alias` | When you sent an alias; names it |
| `x-kyma-cost-usd` | Non-streaming replies. What the call cost you, in USD. The Anthropic body has no field for a price, so it rides here |
| `x-kyma-fallback` | `true` when a fallback route or model answered |
| `x-kyma-served-model` | Only when a different model answered; names it |
| `x-kyma-max-tokens-clamped` | When your balance could not pay for the full `max_tokens`; the value Kyma sent instead. `x-kyma-credits-have` carries your balance |

## Errors

Every error on this endpoint uses Anthropic's envelope, so an Anthropic SDK reads it as one: `type: "error"` on top, an Anthropic error type in `error.type`, and `request_id` at the top level. Kyma adds its own `code` next to the Anthropic type:

```json theme={null}
{
  "type": "error",
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "...",
    "param": null,
    "retryable": true,
    "request_id": "req_…",
    "doc_url": "https://docs.kymaapi.com/api-reference/errors#rate_limit_exceeded"
  },
  "request_id": "req_…"
}
```

| Status | `error.type` | `error.code` | What to do |
| - | - | - | - |
| `400` | `invalid_request_error` | [`invalid_json`](/api-reference/errors#invalid_json), [`missing_parameter`](/api-reference/errors#missing_parameter), [`wrong_endpoint`](/api-reference/errors#wrong_endpoint) | Fix the request; `wrong_endpoint` names the endpoint that serves the model |
| `400` | `invalid_request_error` | [`unsupported_content`](/api-reference/errors#unsupported_content) | An image the model cannot take, an unsupported image source, or a document without a text source. Remove the block, or pick a model that accepts images |
| `400` `413` `422` | `invalid_request_error` | [`request_rejected`](/api-reference/errors#request_rejected) | The model rejected the request; retrying the same body fails the same way |
| `401` | `authentication_error` | [`missing_api_key`](/api-reference/errors#missing_api_key), [`invalid_api_key`](/api-reference/errors#invalid_api_key) | Check `x-api-key` or `Authorization` |
| `402` | `billing_error` | [`insufficient_credits`](/api-reference/errors#insufficient_credits), [`model_requires_paid`](/api-reference/errors#model_requires_paid) | Top up, or pick a model with `free_tier: true`. The body also carries `balance`, `required`, `topup_url` and `details.hint` |
| `403` | `permission_error` | [`route_refused`](/api-reference/errors#route_refused) | Every route for the model refused this content; send it to a model from `error.suggested_models` |
| `404` | `not_found_error` | [`model_not_found`](/api-reference/errors#model_not_found) | Fix the model id; `did_you_mean` and `suggested_models` name close matches |
| `413` | `request_too_large` | [`request_too_large`](/api-reference/errors#request_too_large) | Body over 25 MB: split the messages or downscale images |
| `429` | `rate_limit_error` | [`rate_limit_exceeded`](/api-reference/errors#rate_limit_exceeded) | Back off. `Retry-After: 60`, plus `x-ratelimit-limit-requests`, `x-ratelimit-remaining-requests`, `x-ratelimit-reset-requests` |
| `500` | `api_error` | [`internal_error`](/api-reference/errors#internal_error) | Retry once; if it repeats, send us the `request_id` |
| `502` | `api_error` | [`upstream_invalid_response`](/api-reference/errors#upstream_invalid_response) | Retry |
| `503` | `overloaded_error` | [`provider_unavailable`](/api-reference/errors#provider_unavailable), [`model_unavailable`](/api-reference/errors#model_unavailable) | Retry after `Retry-After: 5`; on `model_unavailable`, pick another model |

A stream that fails after it started ends with `event: error` and `error.code: "stream_interrupted"` (`overloaded_error`). Retry the whole request.

<RequestExample>
  ```bash cURL theme={null}
  curl https://kymaapi.com/v1/messages \
    -H "x-api-key: kyma-your-api-key" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "deepseek-v4-flash",
      "max_tokens": 1024,
      "messages": [
        {"role": "user", "content": "Hello!"}
      ]
    }'
  ```

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

  client = Anthropic(base_url="https://kymaapi.com", api_key="kyma-your-api-key")
  message = client.messages.create(
      model="deepseek-v4-flash",
      max_tokens=1024,
      messages=[{"role": "user", "content": "Hello!"}],
  )
  ```
</RequestExample>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.