Anthropic Messages

Official docs: Messages · Streaming messages · Count tokens

POST /v1/messages is the Anthropic-native wire entrypoint: the auth header, message structure, and event-stream names all keep Claude's shape, so Claude SDK, Claude Code, and similar clients only need to point their base URL at ModelGo.

ItemValue
EndpointPOST /v1/messages
Base URL (Anthropic SDK)https://api.modelgo.ai (no /v1)
Authenticationx-api-key: $MODELGO_API_KEY
Version headeranthropic-version, optional; defaults to 2023-06-01
Protocol valueanthropic_messages

Request examples

bash
curl https://api.modelgo.ai/v1/messages \
  -H "x-api-key: $MODELGO_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<model>",
    "max_tokens": 1024,
    "system": "You are a concise assistant.",
    "messages": [{"role": "user", "content": "Introduce ModelGo in one sentence."}]
  }'
python
import os
import anthropic

client = anthropic.Anthropic(
    api_key=os.environ["MODELGO_API_KEY"],
    base_url="https://api.modelgo.ai",
)

msg = client.messages.create(
    model="<model>",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Introduce ModelGo in one sentence."}],
)
print(msg.content[0].text)

Common fields

FieldRequiredDescription
modelYesPlatform logical model name
max_tokensYesOutput cap
messagesYesMessage array; role is user / assistant, content is a string or block array
systemNoSystem prompt, kept separate from messages
temperature / top_pNoSampling parameters
stop_sequencesNoStop sequences
tools / tool_choiceNoTool definitions and selection; return tool_result as a content block inside a user message
streamNotrue returns the native event stream

The model in the response may be the upstream's internal name (for example pa/venus-cathedral-5), which differs from the requested logical name; billing and policy follow the requested model and the console configuration.

Streaming events

Streaming keeps Anthropic's native event: frames; the gateway never rewrites them into OpenAI's data:-only SSE. The order is message_start → content_block_start → several content_block_delta → content_block_stop → message_delta → message_stop. There is no data: [DONE] sentinel; the stream ends on message_stop.

usage on message_start carries input and cache counts; usage on message_delta carries output counts. Settlement bills the sum of both.

Token counting

POST /v1/messages/count_tokens is estimated locally by the gateway and never forwarded upstream: it counts input_tokens over system, messages, and tools, which is how clients such as Claude Code decide when to compact context. The endpoint is still gated by the model catalog and policy, but it is not billed.

bash
curl https://api.modelgo.ai/v1/messages/count_tokens \
  -H "x-api-key: $MODELGO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"<model>","messages":[{"role":"user","content":"hello"}]}'

Key conventions

  • When a logical model does not declare anthropic_messages, this entrypoint answers HTTP 400 with error_class=model_protocol_not_offered (app_error_id=4005).
  • The error envelope is Anthropic-shaped: {"type":"error","error":{"type":"authentication_error","message":"...","code":401,"metadata":{...}}}, plus a top-level trace_id.
  • GET /v1/models returns an Anthropic-shaped model list (data[].display_name) when the request carries both x-api-key and anthropic-version.
  • Request bodies are capped at 10 MiB.
  • A request that reached the upstream but then failed settles at the reserved amount; see Errors & Rate Limits.

Client setup for Claude Code and friends is in Claude Code; the comparison across all three text entrypoints is in the text generation overview.