Anthropic messages
Anthropic messages
POST /api/v1/messages
The Anthropic Messages API. Claude Code, Cursor and Zed speak only this wire and have no
fallback, so a failing endpoint here means the gateway is unusable to them rather than
degraded.
Auth accepts x-api-key as well as Authorization: Bearer, so an Anthropic SDK works
with only its base URL changed.
Request
| Field | Type | Notes |
|---|---|---|
model |
string | An id from GET /models. |
max_tokens |
integer | Required by this wire, unlike the OpenAI paths. |
messages |
array | Anthropic message objects. |
system |
string or array | System prompt, as a string or content blocks. |
stream |
boolean | Server-sent events. |
tools |
array | Anthropic tool definitions. |
tool_choice |
object | Left alone when you omit it. |
curl https://hisoka.ai/api/v1/messages \
-H "x-api-key: $HISOKA_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "glm-5.3-flash",
"max_tokens": 256,
"messages": [{ "role": "user", "content": "Name three prime numbers." }]
}'
Response
The Anthropic envelope, with the hisoka billing block added:
{
"id": "msg-01M73N2...",
"type": "message",
"role": "assistant",
"model": "glm-5.3-flash",
"content": [{ "type": "text", "text": "2, 3, 5." }],
"stop_reason": "end_turn",
"usage": { "input_tokens": 18, "output_tokens": 8 },
"hisoka": { "usd_micro_charged": 14, "balance": "4.819986" }
}
stop_reason carries the Anthropic vocabulary (end_turn, max_tokens, tool_use), not
the OpenAI one, because the client reading it expects that.
Errors use the Anthropic shape
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key (invalid_api_key)",
"code": "invalid_api_key"
},
"request_id": "01M73N2HP4HDDZH803J1C120HT"
}
Our own code is carried alongside the Anthropic error.type, so a client can branch on
either. Sending an OpenAI-shaped error to Claude Code is the failure this shape prevents.
Count tokens
POST /api/v1/messages/count_tokens
curl https://hisoka.ai/api/v1/messages/count_tokens \
-H "x-api-key: $HISOKA_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"ping"}]}'
{ "input_tokens": 6 }
Answered locally rather than proxied, so a client that calls it before every turn does not
double the upstream request count. It is an estimate: the right shape for budgeting a
context window, not a figure to bill against.
A tool_choice the caller leaves unspecified stays unspecified. Mapping it to required
would forbid the model from answering without a tool call, and an agent then loops forever
on valid 200 responses. If an agent repeats the same tool indefinitely, check the client
before the gateway.
Base URL, one more time
https://hisoka.ai/api/v1, nothing deeper. The SDK appends /v1/messages itself. The
gateway collapses a repeated version segment but never strips a single one, because
clients that send it once must keep working.