POST /v1/messages
Anthropic Messages API compatible endpoint
Generate a response using the Anthropic Messages API format. This endpoint is compatible with the Anthropic SDK and Claude Code.
Endpoint
POST https://api.runars.ca/v1/messagesAuthentication
Include your API key:
-H "x-api-key: sk-runars-..."Or use Bearer token:
-H "Authorization: Bearer sk-runars-..."Request body
For a comparison of common parameters across all endpoints, see Parameters Reference.
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model identifier, must be "glm-5.2" |
max_tokens | integer | Yes | Maximum tokens in the response (1–8000) |
messages | array | Yes | Array of message objects with role and content |
stream | boolean | No | Enable streaming (default: false) |
tools | array | No | Array of tool/function definitions (optional for tool calling) |
tool_choice | string|object | No | Which tool to use ("auto", "required", or specific tool name) |
system | string | No | System prompt/instructions |
Message format
Each message in the messages array must have:
{
"role": "user" or "assistant",
"content": "text content" or [
{ "type": "text", "text": "..." },
{ "type": "tool_use", "id": "...", "name": "...", "input": {...} },
{ "type": "tool_result", "tool_use_id": "...", "content": "..." }
]
}Response (non-streaming)
{
"id": "msg_01ABC...",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "The response text here."
}
],
"model": "glm-5.2",
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 42,
"output_tokens": 15,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0
}
}Response (streaming)
With stream: true, the endpoint returns server-sent events:
event: message_start
data: {"type":"message_start","message":{"id":"msg_...","type":"message",...}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"The "}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"response "}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":15}}
event: message_stop
data: {"type":"message_stop"}Examples
Simple text request
curl https://api.runars.ca/v1/messages \
-H "x-api-key: sk-runars-..." \
-H "content-type: application/json" \
-d '{
"model": "glm-5.2",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": "What is the capital of France?"
}
]
}'Using the Anthropic SDK with streaming
import Anthropic from "@anthropic-ai/sdk"
const anthropic = new Anthropic({
baseURL: "https://api.runars.ca",
apiKey: process.env.ANTHROPIC_API_KEY,
})
const stream = anthropic.messages.stream({
model: "glm-5.2",
max_tokens: 1024,
messages: [
{
role: "user",
content: "Tell me a short story about a robot.",
},
],
})
stream.on("text", (text) => {
process.stdout.write(text)
})
await stream.finalMessage()With tool calling
curl https://api.runars.ca/v1/messages \
-H "x-api-key: sk-runars-..." \
-H "content-type: application/json" \
-d '{
"model": "glm-5.2",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "Get the current weather",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name"
}
},
"required": ["location"]
}
}
],
"messages": [
{
"role": "user",
"content": "What is the weather in Toronto?"
}
]
}'The response will include a tool_use content block with the tool name and input. You can then send the tool result back in a subsequent message.
Web search
Add Anthropic's web search server tool and Runars executes the searches for you — no client round-trips:
{
"model": "glm-5.2",
"max_tokens": 1024,
"tools": [
{
"type": "web_search_20250305",
"name": "web_search",
"max_uses": 5,
"allowed_domains": ["example.com"]
}
],
"messages": [
{ "role": "user", "content": "What happened in the news today?" }
]
}- Gateway-executed: searches run server-side at Runars; the model sees results and answers with citations in one call. No
tool_usestops, no client execution. - Response blocks:
server_tool_use(the query) andweb_search_tool_result(the sources) appear alongside the citedtextblock, andusage.server_tool_use.web_search_requestsreports the count. - Multi-turn: pass the assistant's
server_tool_use/web_search_tool_resultblocks back unchanged — theencrypted_contentblobs are opaque round-trip state. - Options:
max_uses(cap per request, default 5),allowed_domains/blocked_domains, anduser_locationlocalization are honored. - Billing: $10 / 1,000 executed searches (standard rate) plus normal token costs; errored searches are not billed.
- Not supported here: other server tools (
web_fetch,code_execution, …) are rejected with a 400, and/v1/chat/completionsdoes not support web search at all.
Error responses
400 Bad Request
Missing required field:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "Missing required field: max_tokens"
}
}401 Unauthorized
Invalid or missing API key:
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
}402 Payment Required
Insufficient credit balance:
{
"type": "error",
"error": {
"type": "billing_error",
"message": "Insufficient credits"
}
}429 Too Many Requests
Rate limit exceeded:
{
"type": "error",
"error": {
"type": "rate_limit_error",
"message": "Rate limit exceeded"
}
}The response includes a Retry-After header.
Token usage
- Input tokens: Count towards pricing and rate limits.
- Output tokens: Count towards pricing and rate limits.
- Cache write tokens (if using prompt caching): Billed at 1.25× (5m TTL) or 2× (1h TTL) the input token rate.
- Cache read tokens: Billed at 0.1× the input token rate.
See Pricing for details.