Messages
Generates a model response in the Anthropic Messages format. The gateway translates the request to Chat Completions, sends it to the model, and translates the response back. Each parameter below is marked with what the translation does with it today.
/messageshttps://api.bricksum.com/v1/messagesAuthentication
Authentication is the same on every endpoint the gateway fronts, and is documented on the API Reference page.
Request body
Support status
- supported
- The gateway handles it, or a published measurement shows it works.
- passed through
- Forwarded to the model server; not verified by Kiln.
- ignored
- Accepted with 200, but not applied. The rest of the response is normal.
- not supported
- Rejected with an error, or not working on the models named in the description.
Common parameters
These are documented once on the API Reference page. Listed here with what this endpoint does differently.
modelstringsupportedOptional here. When the field is empty or missing, the gateway uses its configured default model. An unknown ID — an Anthropic model ID included — is rejected with 404 (not_found_error).
messagesarrayrequiredsupportedAn empty or missing array is rejected with 400 (invalid_request_error). content is a string or an array of content blocks, in the shapes below. A message with any other role is treated as a user message.
user message
rolestringrequiredsupportedSet to "user".
- Allowed values
- user
content[].type= "text"objectsupportedText. Consecutive text blocks are joined into one string.
content[].type= "image"objectsupportedTranslated to an image_url part. A base64 source becomes a data: URL, and a url source is forwarded as sent. It works only on models whose input includes images; see the Models page.
content[].type= "tool_result"objectsupportedTranslated to a tool message whose tool_call_id is tool_use_id, in block order. content is a string or text blocks; blocks of other types inside it are dropped. is_error is not forwarded.
content[].type= "document"objectignoredDropped before the request reaches the model. The same applies to block types that are not listed here.
assistant message
rolestringrequiredsupportedSet to "assistant".
- Allowed values
- assistant
content[].type= "text"objectsupportedAn earlier model reply.
content[].type= "tool_use"objectsupportedTranslated to a tool_calls entry with the same id and name. input is sent as a compact JSON string.
content[].type= "thinking"objectignoredthinking and redacted_thinking blocks are dropped. The model does not receive its earlier reasoning text.
system message
rolestringrequiredsupportedA message with role "system" inside messages becomes a system message at that position. Only its text is kept.
- Allowed values
- system
max_tokensintegersupportedA value above 32,768 is lowered to 32,768 instead of being rejected, which keeps room for the prompt in the context window. When the field is missing or 0, it is not forwarded and the model server applies its own default.
streambooleansupportedThe stream is a sequence of Anthropic events, listed under Stream events below.
- Default
- false
toolsarraysupportedA tool with a name and an input_schema is translated to a function definition.
custom tool
namestringrequiredsupportedThe name the model uses in tool_use blocks.
descriptionstringsupportedWhat the tool does. The model server rejects a function without a description with 400.
input_schemaobjectrequiredsupportedJSON Schema of the tool input. It becomes the function parameters.
built-in tool
typestringignoredA tool without an input_schema, such as bash_20250124, is skipped. The model cannot run Anthropic server tools, so it does not see them.
tool_choice= {"type": "auto"}objectsupportedTranslated to tool_choice: "auto", and forwarded only when at least one custom tool is sent.
tool_choice= {"type": "any"} | {"type": "tool", ...}objectnot supportedForced tool choice. any is translated to tool_choice: "required", and tool to the named function. On qwen3-32b (measured 2026-09-26), forced tool choice fails without a clear error: tool_choice "required" returns HTTP 500 with a plain-text "Internal Server Error" body, and naming a function returns 200 with empty arguments (finish_reason "stop"). Neither is a 4xx, so do not retry it — send tool_choice "auto" only.
tool_choice= {"type": "none"}objectpassed throughTranslated to tool_choice: "none" and forwarded to the model server; not verified by Kiln.
Only on this endpoint
systemstring | arraysupportedSystem prompt: a string, or an array of text blocks. Each text block becomes one system message at the start of the conversation, in order. Blocks of other types are dropped.
tool_choice.disable_parallel_tool_usebooleanpassed throughtrue is translated to parallel_tool_calls: false and forwarded to the model server; this translation was not measured by Kiln. On qwen3-32b the parallel_tool_calls setting is not applied, which is not the same as replies holding one call: even with parallel_tool_calls: false, one reply can carry several tool calls. Answer every entry in tool_calls with its own tool message.
thinkingobjectsupportedtype "enabled" or "adaptive" is translated to reasoning_effort: "medium". budget_tokens is not used. With any other type, no reasoning_effort is sent.
output_config.effortstringsupportedTranslated to reasoning_effort, and takes precedence over thinking. max, xhigh and ultra are lowered to high. Other values are dropped.
- Allowed values
- low, medium, high
temperaturenumberpassed throughCopied to the chat request and forwarded to the model server; not verified by Kiln.
top_pnumberpassed throughCopied to the chat request and forwarded to the model server; not verified by Kiln.
top_kintegerignoredAccepted, but dropped. The translation has no matching chat parameter.
stop_sequencesarrayignoredTranslated to stop, which is accepted but not applied today. Generation continues past the stop string, and stop_sequence in the response is null.
cache_controlobjectignoredAccepted on any block, tool or system entry, and dropped. Prefix caching on the model server does not depend on it; see usage.cache_read_input_tokens.
metadataobjectignoredAccepted, but dropped. The same applies to context_management.
Fields that are not listed here are dropped before the request reaches the model server. They do not cause an error.
Response body
| Field | Type | Description |
|---|---|---|
| id | string | "msg_" followed by the ID of the underlying chat completion. |
| type | string | "message". |
| role | string | "assistant". |
| model | string | The model ID of the request. |
| content[] | array | Output blocks in this order: one thinking block when the model returned reasoning text, one text block, then one tool_use block per tool call. Do not assume content[0] is text. |
| content[]. | string | Reasoning text of a thinking block. The block carries no signature. |
| content[]. | string | Generated text of a text block. |
| content[]. | object | Arguments of a tool_use block, next to id and name. Arguments that are not a JSON object are kept as a string under _malformed_arguments. |
| stop_reason | string | "end_turn" (finish_reason stop), "max_tokens" (length) or "tool_use" (tool_calls, or any reply that has tool calls). Other finish reasons map to "end_turn". |
| stop_sequence | null | null in every response. |
| usage. | integer | Input tokens, copied from prompt_tokens of the chat completion. |
| usage. | integer | Output tokens, including reasoning tokens. |
| usage. | integer | Input tokens served from the prefix cache. 0 when the model server reports none. |
| X-Neocloud-Generation-Id | header | Response header with the ID of the usage event for this request. Store it with your logs. The Messages usage object has no cost field. |
Stream events
With stream: true, each event has an event: line with its name and a data: line with a JSON object of the same type. The order is message_start, then content_block_start, content_block_delta and content_block_stop for each block, then message_delta and message_stop. One block is open at a time. There is no data: [DONE] line.
| Field | Type | Description |
|---|---|---|
| message_start | event | Opens the message: id, model, empty content. Its usage holds input_tokens: 0 and output_tokens: 0, because the model server reports usage only at the end. |
| content_block_start | event | Opens the block at index. content_block.type is thinking, text or tool_use; a tool_use block carries id and name. |
| content_block_delta | event | New content of the open block. delta.type is text_delta (text), thinking_delta (thinking) or input_json_delta (partial_json). Concatenate partial_json per block, then parse it. |
| content_block_stop | event | Closes the block at index. |
| message_delta | event | delta.stop_reason and usage.output_tokens. The model server sends usage in a chunk after the one with finish_reason, so the gateway reads the stream to its end before it writes this event. The stream does not report input tokens. |
| message_stop | event | The last event of a complete message. |
| ping | event | Sent after 15 seconds without data from the model server, for example during a long reasoning pause. It can arrive at any point, including before message_start. Ignore it. |
| error | event | The last event of a failed stream, in the Anthropic error envelope. A model server error, a read failure or a stream that ends before completion gives api_error. No message_stop follows. |
Errors
After authentication, errors use the Anthropic envelope: {"type": "error", "error": {"type", "message"}}. Branch on the HTTP status and error.type, not on the message text. Rows with an empty error.type cell come from the gateway before the request reaches this endpoint, and use the body shown under the table.
Every status code is listed on the Errors page.
| Status · error.type | Cause | What to do |
|---|---|---|
| 400invalid_request_error | The body is not valid JSON, messages is empty or missing, or a message content is neither a string nor an array of blocks. | Fix the payload. Do not retry as sent. |
| 400invalid_request_error | The model server rejected the translated request, for example more than the model's context window (the Models page lists it per model). error.message carries the model server's message. | Shorten the conversation or fix the parameters. |
| 404not_found_error | The model ID is not in the catalog. | Check the ID against GET /models. |
| 405invalid_request_error | The method is not POST. | Send the request with POST. |
| 429rate_limit_error | The organization already has 8 requests in flight. No rate-limit headers are sent. | Back off exponentially and retry. |
| 502api_error | The model backend returned an error or was unreachable, or its response could not be translated. | Retry with exponential backoff. |
| 503api_error | No model backend is available. | Retry with exponential backoff. |
401, 402, 403 and 429 come from the gateway before the request reaches this endpoint. They are listed once on the API Reference page.
Authentication, credit, budget and rate-limit (requests/min, tokens/min) errors are returned by the gateway before the Anthropic translation. Their body is not the Anthropic envelope:
{
"error": {
"message": "invalid API key",
"type": "authorization"
}
}Limits
- Output: max_tokens is capped at 32,768. A larger value is lowered, not rejected.
- Metering: a Messages request is metered and billed as one chat completion, with the same token counts and the same per-organization limit of 8 concurrent requests.
Context length, request body size, timeouts and the per-organization rate limits apply here as well; they are listed once on the API Reference page.
Headers and retry guidance for 429 are on the Rate limits page.