Anthropic-compatible
Messages
Call models on NoviaHub in the Anthropic Messages format — URL, headers, request parameters, response, streaming events and sample code.
Compatible with Anthropic’s Messages API. Tools such as Claude Code use this endpoint.
POST https://noviahub.com/v1/messagesFor models whose endpoint labels include Anthropic (check on Models & Pricing). When you call a non-Claude model here, NoviaHub converts the protocol automatically; see Protocol conversion for what to watch out for.
Headers
Section titled “Headers”| Header | Required | Description |
|---|---|---|
x-api-key |
One of the two | Your API key. |
Authorization |
One of the two | Bearer <your API key>, as an alternative to x-api-key. |
anthropic-version |
No | Protocol version. If you leave it out, NoviaHub sends 2023-06-01 upstream. |
anthropic-beta |
No | Turns on Anthropic beta features; forwarded upstream as is. Whether it works depends on the model. |
Content-Type |
Yes | application/json |
Request parameters
Section titled “Request parameters”These are the parameters NoviaHub recognises and forwards. Whether a parameter takes effect depends on the model.
| Parameter | Type | Required | Description |
|---|---|---|---|
model |
string | Yes | Model ID, such as claude-sonnet-5. |
messages |
array | Yes | The conversation; structure below. |
max_tokens |
integer | Yes | Maximum tokens to generate. Required by the Anthropic protocol; NoviaHub itself doesn’t check it, so a missing value is left to the upstream to reject or not. |
system |
string / array | No | System prompt: a string, or an array of text blocks (which may carry cache_control). |
temperature |
number | No | Sampling temperature. |
top_p |
number | No | Nucleus sampling. |
top_k |
integer | No | Top-K sampling. |
stop_sequences |
array | No | Stop when any of these strings appears. |
stream |
boolean | No | true returns a stream (SSE). |
tools |
array | No | Tools the model may call. |
tool_choice |
object | No | How tools are chosen. |
thinking |
object | No | Extended thinking, such as {"type": "enabled", "budget_tokens": 2048}. |
metadata |
object | No | Extra data, forwarded as is. |
output_config, output_format |
object | No | Output settings, forwarded as is. |
context_management, container, mcp_servers, cache_control |
— | No | Forwarded as defined by Anthropic. |
Structure of messages
Section titled “Structure of messages”Each message has a role (user or assistant) and content. content is either text or an array of content blocks as defined by Anthropic, for example:
- Text block:
{"type": "text", "text": "..."} - Image block:
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "..."}} - Tool calls and results:
tool_use,tool_result - Thinking block:
thinking(withsignature)
Sample code
Section titled “Sample code”curl https://noviahub.com/v1/messages \ -H "x-api-key: $NOVIAHUB_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Explain what an API is in one sentence."}] }'import os
import anthropic
client = anthropic.Anthropic( base_url="https://noviahub.com", api_key=os.environ["NOVIAHUB_API_KEY"],)
message = client.messages.create( model="claude-sonnet-5", max_tokens=1024, messages=[{"role": "user", "content": "Explain what an API is in one sentence."}],)
print(message.content[0].text)import Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic({ baseURL: 'https://noviahub.com', apiKey: process.env.NOVIAHUB_API_KEY,})
const message = await client.messages.create({ model: 'claude-sonnet-5', max_tokens: 1024, messages: [{ role: 'user', content: 'Explain what an API is in one sentence.' }],})
console.log(message.content[0].type === 'text' ? message.content[0].text : message.content)The Anthropic SDK’s base URL is just https://noviahub.com; don’t include /v1.
Response
Section titled “Response”| Field | Description |
|---|---|
id |
ID of this reply. |
type |
Always message. |
role |
Always assistant. |
model |
Model ID. |
content[] |
Content blocks. Text is in blocks of type text, under text; there may also be thinking, tool_use and other blocks. |
stop_reason |
Why generation stopped, such as end_turn (finished), max_tokens (hit the limit), tool_use (wants to call a tool). |
usage.input_tokens |
Input tokens. |
usage.output_tokens |
Output tokens. |
usage.cache_creation_input_tokens |
Input tokens written to the cache. |
usage.cache_read_input_tokens |
Input tokens read from the cache. |
{ "id": "msg_mock123", "type": "message", "role": "assistant", "model": "claude-sonnet-5", "content": [{ "type": "text", "text": "Hello from the mock upstream." }], "stop_reason": "end_turn", "stop_sequence": null, "usage": { "input_tokens": 12, "output_tokens": 7, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0 }}Streaming
Section titled “Streaming”With "stream": true, the response arrives as SSE events in the same order as Anthropic’s:
message_start: start, with the message’s basic information.content_block_start: a content block starts.content_block_delta: an increment of the block; text is indelta.text(delta.typeistext_delta).content_block_stop: the block ends.message_delta: the stop reason (delta.stop_reason) and usage (usage).message_stop: everything is done.
The usage in message_delta is authoritative. NoviaHub adds input_tokens there so you get input and output counts in one place.
event: message_startdata: {"type":"message_start","message":{"id":"msg_mock123","type":"message","role":"assistant","model":"claude-sonnet-5","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":12,"output_tokens":1,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}
event: content_block_startdata: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_deltadata: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}
event: content_block_deltadata: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" from the mock upstream."}}
event: content_block_stopdata: {"type":"content_block_stop","index":0}
event: message_deltadata: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":7,"input_tokens":12}}
event: message_stopdata: {"type":"message_stop"}import os
import anthropic
client = anthropic.Anthropic( base_url="https://noviahub.com", api_key=os.environ["NOVIAHUB_API_KEY"],)
with client.messages.stream( model="claude-sonnet-5", max_tokens=1024, messages=[{"role": "user", "content": "Write a four-line poem."}],) as stream: for text in stream.text_stream: print(text, end="", flush=True)import Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic({ baseURL: 'https://noviahub.com', apiKey: process.env.NOVIAHUB_API_KEY,})
const stream = client.messages.stream({ model: 'claude-sonnet-5', max_tokens: 1024, messages: [{ role: 'user', content: 'Write a four-line poem.' }],})
stream.on('text', (text) => process.stdout.write(text))await stream.finalMessage()Not supported
Section titled “Not supported”POST /v1/messages/count_tokens(token counting) is not available and returns 404.
Common errors
Section titled “Common errors”Errors from /v1/messages come in two shapes; see API overview · Error format.
| HTTP status | Cause |
|---|---|
| 400 | Missing model, or the body isn’t valid JSON. |
| 401 | The key is invalid, disabled, expired or out of quota. |
| 403 | The key isn’t allowed to use this model, the IP isn’t on the allow list, or the account balance is too low. |
| 503 | Wrong model ID, or no channel is currently available for the model. |
See Errors and troubleshooting for details.