Messages (Anthropic)
POST /v1/messages, the Anthropic-compatible Messages endpoint, its request parameters, response shape, and cache-token billing.
Generate a model response using the Anthropic Messages API shape. This is a second API family alongside Chat Completions, for models that support it. Use it as a drop-in for the Anthropic SDKs and for Claude Code.
POST https://inference.openrelay.inc/v1/messagesThe endpoint implements the Anthropic Messages API format; Anthropic features, including tool use, work as documented.
Which models support this
Not every model serves the Messages family. Check a model's supported_apis
field from GET /v1/models rather than assuming:
{
"id": "openrelay/glm-5.2",
"supported_apis": ["chat_completions", "messages"]
}openrelay/glm-5.2 is the current example: it supports both chat_completions
and messages on the same model id. A request to a model that doesn't list
messages in supported_apis returns 400 unsupported_api.
Authentication
Send your vl_ API key as x-api-key (the Anthropic SDK convention). The
gateway also accepts Authorization: Bearer. See
Authentication for both header forms.
curl https://inference.openrelay.inc/v1/messages \
-H "x-api-key: $OPENRELAY_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{ ... }'Request
The body follows the Anthropic Messages shape. Three fields matter most:
| Field | Type | Description |
|---|---|---|
model | string (required) | An OpenRelay public model id, e.g. openrelay/glm-5.2. See Models. |
max_tokens | integer (required) | Upper bound on tokens to generate. Unlike Chat Completions, Messages requires this field. |
messages | array (required) | The conversation so far: { "role": "user" | "assistant", "content": "…" } objects. Do not put a system role here; use the top-level system field instead. |
| Field | Type | Description |
|---|---|---|
system | string or array | The system prompt, as a top-level field, not a message with role: "system". |
temperature | number | Sampling temperature. |
top_p | number | Nucleus-sampling probability mass. |
stop_sequences | array | Sequence(s) that halt generation. |
stream | boolean | Stream the response as event-typed Server-Sent Events. See Streaming below. |
tools | array | Anthropic-shape tool definitions. |
The endpoint accepts the Anthropic Messages request format, including
tools and tool_choice. Parameters a model does not support are rejected
with a standard error.
Example request
curl https://inference.openrelay.inc/v1/messages \
-H "x-api-key: $OPENRELAY_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "openrelay/glm-5.2",
"max_tokens": 256,
"system": "You are a terse assistant.",
"messages": [
{ "role": "user", "content": "Name three primary colors." }
]
}'Response
A unary (non-streaming) response is an Anthropic message object:
{
"id": "msg_…",
"type": "message",
"role": "assistant",
"model": "openrelay/glm-5.2",
"content": [
{ "type": "text", "text": "Red, green, and blue." }
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 24,
"output_tokens": 7,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
}
}| Field | Description |
|---|---|
id | Unique id for this message. |
model | Always the public OpenRelay model id you requested. |
content | An array of content blocks (text, thinking, tool_use, …) making up the reply. |
stop_reason | Why generation stopped. |
usage | Token counts for the request. See Usage and cache billing below. |
Response model id
The model field in every response is the OpenRelay model id you requested.
Streaming
Set "stream": true to receive the response as event-typed Server-Sent
Events, matching the Anthropic dialect: each event carries an event: line
naming the event type, followed by a data: line:
event: message_start
data: {"type":"message_start","message":{"id":"msg_…","model":"openrelay/glm-5.2","usage":{"input_tokens":24,"cache_read_input_tokens":0}}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Red"}}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":7}}
event: message_stop
data: {"type":"message_stop"}This is different from the Chat Completions stream,
which is data-only frames with no event: line. Key differences:
event:lines are load-bearing and always present, so the Anthropic SDKs dispatch on them normally.- Usage arrives in two places:
message_startcarriesinput_tokensand the cache counters,message_deltacarriesoutput_tokens. Combine both to get the full usage for the request. - There is no
[DONE]sentinel. The stream ends atmessage_stop.
Usage and cache billing
Usage is reported using Anthropic's field names, which differ from the Chat
Completions shape in one important way: input_tokens excludes cache
reads. There is no subtraction to do yourself.
usage field | Billing dimension | Rate |
|---|---|---|
input_tokens | Input (fresh, excludes cache reads) | Model's input rate |
cache_read_input_tokens | Cached input | Model's discounted cached-input rate |
cache_creation_input_tokens | Cache write | Model's cache-write rate |
output_tokens | Output | Model's output rate |
{
"usage": {
"input_tokens": 28,
"cache_read_input_tokens": 2496,
"cache_creation_input_tokens": 0,
"output_tokens": 83
}
}Cache write is Messages-only
cache_creation_input_tokens (the cache-write dimension) is only reported
by the Messages family; Chat Completions has no equivalent field. See
Pricing & billing for current per-model rates on
all four dimensions.
Errors
Errors use the same status codes and error body as the rest of the gateway
(see Errors): 401 for a missing or invalid key,
402 for insufficient balance, 403 for an account hold, 404 if the model
doesn't exist, and 429/502/503 for transient errors. One
Messages-specific case:
| Status | code | Cause |
|---|---|---|
400 | unsupported_api | The model doesn't serve the Messages family. Check supported_apis on GET /v1/models. |
Using the Anthropic SDKs
curl https://inference.openrelay.inc/v1/messages \
-H "x-api-key: $OPENRELAY_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "openrelay/glm-5.2",
"max_tokens": 256,
"messages": [{ "role": "user", "content": "Hello!" }]
}'Install the anthropic package, then
point it at OpenRelay's host root (no /v1 suffix, the SDK appends its own
path):
pip install anthropicfrom anthropic import Anthropic
client = Anthropic(
base_url="https://inference.openrelay.inc",
api_key="vl_your_api_key",
)
resp = client.messages.create(
model="openrelay/glm-5.2",
max_tokens=256,
messages=[{"role": "user", "content": "Hello!"}],
)
print(resp.content[0].text)Install @anthropic-ai/sdk:
npm install @anthropic-ai/sdkimport Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
baseURL: 'https://inference.openrelay.inc',
apiKey: process.env.OPENRELAY_API_KEY, // 'vl_...'
});
const resp = await client.messages.create({
model: 'openrelay/glm-5.2',
max_tokens: 256,
messages: [{ role: 'user', content: 'Hello!' }],
});
console.log(resp.content[0].type === 'text' ? resp.content[0].text : '');Point Claude Code's environment variables at OpenRelay to run it on any Messages-capable model:
export ANTHROPIC_BASE_URL=https://inference.openrelay.inc
export ANTHROPIC_AUTH_TOKEN=$OPENRELAY_API_KEY
export ANTHROPIC_MODEL=openrelay/glm-5.2
claude # agentic coding, now on openrelay/glm-5.2Limits
The request body is capped at 10 MiB; a larger body is rejected with
413 Payload Too Large. See Errors.