Docs · API compatível com Anthropic
Messages
O dialeto Messages da Anthropic. Use com ferramentas e SDKs que só falam essa API, principalmente o Claude Code. Qualquer modelo do gateway pode responder, não só os modelos da Anthropic: o gateway traduz a requisição.
POST/v1/messages#
- Auth: a sua chave de API em
x-api-keyouAuthorization: Bearer. Os headersanthropic-versioneanthropic-betasão aceitos e ignorados. - Limite: 20 requisições por minuto por conta por padrão, um contador que todos os endpoints
/v1dividem com os outros endpoints que têm um número por minuto próprio. Veja limites e cotas. - Corpo: JSON.
curl -s "$SHVIA_URL/v1/messages" \
-H "x-api-key: $SHVIA_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "'"$SHVIA_MODEL"'",
"max_tokens": 256,
"messages": [{ "role": "user", "content": "Say hello in one short sentence." }]
}'Requisição#
| Campo | Notas |
|---|---|
model | obrigatório. Um id de modelo de modelos. Um nome real de modelo da Anthropic não é mapeado. Se ele não está na sua lista e não tem @server, não é recusado: o servidor padrão responde com outro modelo, então confira model na resposta. Com um @server explícito que o gateway não tem, você recebe 404 |
messages | obrigatório, de 1 a 200 mensagens com role user ou assistant. content é uma string ou uma lista de blocos |
system | uma string, ou uma lista de blocos de texto |
collections | lista opcional de 1 a 5 ids de suas coleções. Os trechos delas que dizem respeito à última mensagem do usuário são acrescentados a system. Não faz parte da API da Anthropic. As recusas trazem error.code, e os headers X-Inference-Collections e X-Inference-Excerpts dizem o que foi usado |
stream | true para server-sent events |
tools, tool_choice | ferramentas de função. tool_choice é um objeto cujo type é auto, any, none ou tool (com um name). Uma string solta é ignorada, assim como um tool_choice enviado sem tools |
max_tokens | opcional aqui, ao contrário da API da Anthropic. Se você enviar, tem de ser um inteiro de pelo menos 1. Não é aplicado |
Os blocos de conteúdo entendidos são text, tool_use (numa mensagem do assistente) e tool_result (numa mensagem do usuário).
O que é descartado em silêncio#
Nada abaixo produz erro. A requisição tem sucesso e o item é ignorado:
image,document,thinkinge qualquer outro tipo de bloco. Uma mensagem feita só desses blocos some da conversa, e uma requisição que só tem mensagens assim pode ser recusada pelo modelo.temperature,top_p,top_k,stop_sequences,thinking,metadata,cache_control, e todo outro campo de nível superior.- Ferramentas tipadas, como busca na web ou uma ferramenta de computador, são tratadas como ferramentas de função comuns, pelo nome.
Resposta#
{
"id": "msg_0123456789abcdef01234567",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4-6@anthropic",
"content": [{ "type": "text", "text": "Hello! Nice to meet you." }],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": { "input_tokens": 14, "output_tokens": 8 }
}stop_reasonétool_usequando a resposta traz chamadas de ferramenta, eend_turnnos outros casos. Nunca émax_tokens.- Uma chamada de ferramenta é um bloco
{"type": "tool_use", "id": "…", "name": "…", "input": {…}}.inputé sempre um objeto. usagetem sóinput_tokenseoutput_tokens: não há contadores de cache.- Como em chat completions,
modelé o id que o gateway resolveu. Ele não mostra um fallback para o seu modelo padrão.
Streaming#
Com "stream": true a resposta é text/event-stream e cada evento é event: <name> mais data: {…}. Os eventos são exatamente estes:
| Evento | Quando |
|---|---|
message_start | o primeiro. usage.input_tokens é sempre 0 aqui |
content_block_start | um bloco de texto abre com o primeiro texto, e cada chamada de ferramenta abre um bloco |
content_block_delta | text_delta para texto; para uma chamada de ferramenta, um input_json_delta que traz os argumentos inteiros |
content_block_stop | um bloco fecha |
message_delta | stop_reason e usage.output_tokens |
message_stop | o último, num fim normal |
error | no lugar dos dois últimos, quando a resposta falha |
event: message_start
data: {"type":"message_start","message":{"id":"msg_…","type":"message","role":"assistant","model":"claude-sonnet-4-6@anthropic","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0}}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":8}}
event: message_stop
data: {"type":"message_stop"}Não há evento ping. Os tokens de entrada não são informados num stream, então use o usage sem stream ou a contagem de tokens quando precisar deles.
Erros#
Os erros usam o formato da Anthropic {"type": "error", "error": {"type": "…", "message": "…"}}, com duas exceções: um 401 usa o formato da OpenAI, e um 429 é o simples {"message": "Too Many Attempts."} quando você envia Accept: application/json.
| Status | error.type | Quando |
|---|---|---|
| 400 | invalid_request_error | o corpo falhou na validação |
| 401 | o formato da OpenAI, code invalid_api_key | a chave não é válida |
| 403 | permission_error | o modelo não é permitido para o seu grupo, ou uma cota acabou |
| 404 | not_found_error | o id tem um servidor e o gateway não tem esse modelo lá |
| 429 | nenhum | limite de requisições atingido. Leia Retry-After |
| 502 | api_error | o modelo não devolveu nada, ou não pôde ser alcançado |
| 504 | timeout_error | o modelo parou no meio da resposta. O corpo acrescenta uma mensagem partial, e X-Inference-Incomplete: read_timeout é enviado |
| o status do provedor | api_error | todos os modelos da cadeia falharam e um provedor recusou a chamada. O status é repassado, e type é api_error seja qual for. Um 401 ou 403 aqui pode vir do provedor do modelo, por exemplo um servidor de modelo que rejeita as credenciais do próprio gateway, e não da sua chave |
POST/v1/messages/count_tokens#
Devolve uma estimativa local do tamanho da entrada, para que clientes como o Claude Code decidam quando compactar. Não chama nenhum modelo e não usa cota, mas conta no limite de requisições.
curl -s "$SHVIA_URL/v1/messages/count_tokens" \
-H "x-api-key: $SHVIA_API_KEY" -H "content-type: application/json" \
-d '{ "model": "'"$SHVIA_MODEL"'", "messages": [{ "role": "user", "content": "Hello, world" }] }'{ "input_tokens": 3 }A resposta traz X-Inference-Tokens-Source: estimate-chars-4: o número é a contagem de caracteres dividida por 4, arredondada para cima, e não um tokenizador. Não vai bater com a contagem de nenhum modelo. As chamadas de ferramenta anteriores no histórico não são contadas, então o histórico longo de um agente sai subcontado. O model não é conferido.
Use com o Claude Code#
Aponte o Claude Code para o host, sem /v1: o cliente acrescenta /v1/messages sozinho.
export ANTHROPIC_BASE_URL="https://ai.shvia.org"
export ANTHROPIC_AUTH_TOKEN="$SHVIA_API_KEY"
export ANTHROPIC_MODEL="$SHVIA_MODEL"
claudeDefinir ANTHROPIC_BASE_URL como https://ai.shvia.org/v1 faz o cliente requisitar /v1/v1/messages, que não existe. A configuração completa, e as outras ferramentas, estão em conecte suas ferramentas.
Um assistente de código pode enviar várias requisições por turno: a própria mensagem, a contagem de tokens e uma nova tentativa quando uma requisição falha. O limite padrão de 20 requisições por minuto é fácil de atingir com um deles, então peça ao seu administrador que o aumente para uso intenso.
Tratamento de dados#
Como os outros endpoints /v1, nada é guardado como conversa, cada chamada é medida, e identificadores comuns no texto são mascarados antes de ele ir para um modelo que não está na infraestrutura do próprio operador. Veja seus dados.