Messages
POST /v1/messages
Generate a reply using the Anthropic Messages protocol. Send a list of conversation messages and the model returns the next assistant message. Ideal when you're using the Anthropic SDK or Claude Code.
This endpoint is compatible with the Anthropic Messages SDK. Point base_url at CrossModel and set model to a CrossModel model ID. Auth uses the x-api-key header.
Endpoint
POST https://api.crossmodel.ai/v1/messages
x-api-key: cm-YOUR_KEY
anthropic-version: 2023-06-01
Content-Type: application/jsonEach request needs an API key in the x-api-key header (Authorization: Bearer also works). Create and manage keys on the console's API Keys page.
1curl https://api.crossmodel.ai/v1/messages \2 -H "Content-Type: application/json" \3 -H "anthropic-version: 2023-06-01" \4 -H "x-api-key: $CROSSMODEL_API_KEY" \5 -d '{6 "model": "anthropic/claude-sonnet-4.6",7 "max_tokens": 1024,8 "system": "You are a helpful assistant.",9 "messages": [10 { "role": "user", "content": "Hello!" }11 ]12 }'Request parameters
| Parameter | Type | Required | Notes |
|---|---|---|---|
model | string | Yes | The model ID to use, e.g. anthropic/claude-sonnet-4.6. Call /v1/models for the full list. |
messages | array | Yes | The conversation so far, in chronological order, with at least one entry. See Message object below. |
max_tokens | integer | Yes | Max tokens to generate for this reply. |
system | string or array | No | A system prompt that sets the model's behavior and persona. |
temperature | number | No | Sampling temperature, typically 0–1. Higher is more random and varied. |
top_p | number | No | Nucleus-sampling threshold. Usually adjust either temperature or top_p, not both. |
top_k | integer | No | Sample only from the K highest-probability candidates. |
stop_sequences | string[] | No | Custom stop sequences. Generation halts at the first match. |
tools | array | No | The tools the model may call. See Function tools below. |
tool_choice | object | No | Controls whether and how the model calls tools. |
metadata | object | No | Request metadata; may include user_id for safety and abuse detection. |
thinking | object | No | Extended-thinking config. type is enabled, disabled, or adaptive; when enabled, provide budget_tokens. The effect depends on the model. |
stream | boolean | No | Whether to stream the result. Default false. |
Message object
messages is a chronological array with at least one message.
| Field | Type | Required | Notes |
|---|---|---|---|
role | string | Yes | The sender's role; only user and assistant. Put the system prompt in the top-level system field, not in messages. |
content | string or array | Yes | The message content. Use a string for plain text; use a content-block array for images or tool content (see Content blocks). |
Content blocks
When content is an array, each element is a content block with a type field:
| type | Fields | Notes |
|---|---|---|
text | text | A piece of text. |
image | source | Image input. source is { "type": "base64", "media_type": ..., "data": ... } or { "type": "url", "url": ... }. |
tool_use | id, name, input | A tool call issued by the assistant. |
tool_result | tool_use_id, content, is_error | The result of running a tool; tool_use_id points at the corresponding tool_use. |
Document and PDF input (the document content block) isn't supported yet.
Function tools
Declare functions the model can call via the tools field. The model returns a tool_use content block when needed; your code runs it and passes the result back as a tool_result content block.
{
"tools": [
{
"name": "get_weather",
"description": "Get current weather for a city.",
"input_schema": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
]
}| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | The function name the model uses to reference the tool. |
description | string | No | What the function does. A clear description helps the model decide when to call it. |
input_schema | object | No | JSON Schema for the function's parameters. |
Example request
curl https://api.crossmodel.ai/v1/messages \
-H "x-api-key: cm-YOUR_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4.6",
"max_tokens": 1024,
"system": "You are a helpful assistant.",
"messages": [
{ "role": "user", "content": "Hello!" }
]
}'Response
A non-streaming request returns a message object.
{
"id": "msg_abc123",
"type": "message",
"role": "assistant",
"model": "anthropic/claude-sonnet-4.6",
"content": [
{ "type": "text", "text": "Hello! How can I help?" }
],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 18,
"output_tokens": 14,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0
}
}| Field | Type | Notes |
|---|---|---|
id | string | A unique ID for this reply. |
type | string | Always message. |
role | string | Always assistant. |
model | string | The model ID used for this request. |
content | array | The generated content blocks. |
stop_reason | string | Why it stopped — see below. |
stop_sequence | string or null | The stop sequence that was matched, or null if none. |
usage | object | Token usage for this request, used for billing. |
Response content blocks
In the response content array, each element is a content block with a type field:
| type | Fields | Notes |
|---|---|---|
text | text | The generated text. |
tool_use | id, name, input | A function call issued by the model. input is the arguments object. |
stop_reason
| Value | Notes |
|---|---|
end_turn | The model finished its reply naturally. |
max_tokens | Hit the max_tokens cap. |
stop_sequence | Matched a stop sequence. |
tool_use | The model switched to issuing a tool call. |
The usage object
| Field | Type | Notes |
|---|---|---|
input_tokens | integer | Input tokens. |
output_tokens | integer | Output tokens. |
cache_creation_input_tokens | integer | Input tokens written to the cache. |
cache_read_input_tokens | integer | Input tokens that hit the cache. |
Streaming response
Set stream to true and the endpoint returns text/event-stream. A reply is made up of these events, in order:
| Event | Notes |
|---|---|
message_start | The message begins, with initial message info. |
content_block_start | A content block begins. |
content_block_delta | An increment of a content block (text_delta, input_json_delta, or thinking_delta). |
content_block_stop | A content block ends. |
message_delta | Carries stop_reason and usage. |
message_stop | The message ends. |
curl https://api.crossmodel.ai/v1/messages \
-H "x-api-key: cm-YOUR_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4.6",
"max_tokens": 1024,
"messages": [{ "role": "user", "content": "Hi" }],
"stream": true
}'Errors
Errors use the Anthropic format:
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "Missing API key."
}
}| HTTP status | error.type | Notes |
|---|---|---|
400 | invalid_request_error | Malformed body JSON, message structure, or parameters. |
401 | authentication_error | API key missing or invalid. |
402 | permission_error | Out of balance or not permitted. |
404 | invalid_request_error | The requested model doesn't exist or is currently unavailable. |
429 | rate_limit_error | Too many requests — rate limited. |
502 | api_error | The model service returned an error or an abnormal response. |
503 | overloaded_error | Model temporarily unavailable — retry shortly. |
500 | api_error | A CrossModel internal error. |