Skip to main content

APIs

Messages API (Anthropic-compatible)

The Anthropic-style /v1/messages endpoint lets you point the Anthropic SDK — or Claude Code — at AI Gateway with an AI Gateway API key. It speaks the Anthropic wire format for requests, responses, streaming events and errors, and it is provider-agnostic: the same request runs against Claude, GPT, Gemini or Bedrock models, translated transparently.

Point the Anthropic SDK at the gateway

The Messages dialect lives under the /anthropic prefix (not /v1): set the SDK base URL to https://<your-caronte>/anthropic and the SDK composes …/anthropic/v1/messages. Authenticate with your AI Gateway key (sk_…) — sent as x-api-key by the Anthropic SDK, or as Authorization: Bearer; both are accepted.

client.ts
import Anthropic from "@anthropic-ai/sdk"; // The SDK sends the key as the `x-api-key` header and appends // `/v1/messages` to the base URL. export const anthropic = new Anthropic({ apiKey: process.env.CARONTE_API_KEY!, baseURL: process.env.CARONTE_ANTHROPIC_BASE_URL ?? "https://<your-caronte>/anthropic", });

tip · Using Claude Code (or any Anthropic client)?

Export two environment variables and Claude Code routes every request through AI Gateway — budgets, tracing, guardrails and PII masking included:
bash
export ANTHROPIC_BASE_URL="https://<your-caronte>/anthropic" export ANTHROPIC_API_KEY="$CARONTE_API_KEY"
The anthropic-version / anthropic-beta headers the SDK sends are accepted but not required — the gateway does not validate them.

This bills the organization: the key spends its own budget and the model comes from the Caronte catalog. To keep using your own claude.ai subscription and have the sessions recorded under your name instead, use Developer tools — same base URL, different credential, and the two are alternatives rather than a combination.

Basic usage

Send a list of messages with a required max_tokens and read the assistant content blocks back.

example.ts
import { anthropic } from "./client"; const message = await anthropic.messages.create({ model: "claude-sonnet-5", max_tokens: 1024, system: "You are a concise assistant.", messages: [ { role: "user", content: "Summarize what AI Gateway does in one sentence." }, ], }); // content is an array of blocks; text blocks carry the answer. const text = message.content .filter((b) => b.type === "text") .map((b) => b.text) .join(""); console.log(text);
quick sanity check
curl https://<your-caronte>/anthropic/v1/messages \ -H "x-api-key: $CARONTE_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-5", "max_tokens": 256, "messages": [{ "role": "user", "content": "ping" }] }'

note · Any model your key can access — not just Claude

Dispatch is provider-agnostic. Pass a Claude model for full Anthropic-native fidelity, or any other model your key is allowed to call (e.g. gpt-4o-mini, a Gemini or Bedrock model) and the gateway translates the Anthropic request to that provider and back. See Provider fidelity for what is preserved on each path.

Streaming

Set stream: true to receive a stream of named Anthropic events (message_start, content_block_delta, message_stop, …) — there is no [DONE] terminator, unlike the OpenAI endpoints.

example.ts
import { anthropic } from "./client"; const stream = anthropic.messages.stream({ model: "claude-sonnet-5", max_tokens: 1024, messages: [{ role: "user", content: "Stream a short haiku about proxies." }], }); for await (const event of stream) { if ( event.type === "content_block_delta" && event.delta.type === "text_delta" ) { process.stdout.write(event.delta.text); } }

Streaming is rejected on keys with active PII masking (400) — masking can't be applied mid-stream.

System prompts & images

The top-level system field takes a string or an array of text blocks. Image blocks accept a base64 or url source and work across providers (base64 is decoded and forwarded).

example.ts
import { anthropic } from "./client"; const message = await anthropic.messages.create({ model: "claude-sonnet-5", max_tokens: 512, system: "Describe images for accessibility.", messages: [ { role: "user", content: [ { type: "text", text: "What is in this picture?" }, { type: "image", source: { type: "base64", media_type: "image/png", data: pngBase64 }, }, ], }, ], });

Tool use

Same request/reply loop as Function calling, in the Anthropic shape: declare tools with an input_schema, read back tool_use blocks, and reply with a tool_result block on the next turn. On non-Claude models these map to native function calling transparently (server-tool variants such as web_search are only honored on the native Anthropic path).

example.ts
import { anthropic } from "./client"; const message = await anthropic.messages.create({ model: "claude-sonnet-5", max_tokens: 1024, tools: [ { name: "get_weather", description: "Get the current weather for a city.", input_schema: { type: "object", properties: { city: { type: "string" } }, required: ["city"], }, }, ], messages: [{ role: "user", content: "What's the weather in Milan?" }], }); const toolUse = message.content.find((b) => b.type === "tool_use"); // → { type: "tool_use", id: "toolu_…", name: "get_weather", input: { city: "Milan" } }

Extended thinking

Enable reasoning with the thinking parameter — reasoning arrives as thinking content blocks before the text blocks. The gateway normalizes it to a single effort dial and translates it to whatever provider your model runs on.

example.ts
import { anthropic } from "./client"; const message = await anthropic.messages.create({ model: "claude-sonnet-5", max_tokens: 4096, thinking: { type: "enabled", budget_tokens: 8192 }, messages: [{ role: "user", content: "Prove there are infinitely many primes." }], });

note · Full behavior lives on its own page

The effort-dial mapping, per-provider conversion table and the translation caveats (signatures, lossy budgets, dropped history thinking) are documented in full on Extended thinking.

Code execution (programmatic tool calling)

The endpoint supports Anthropic's code-execution / programmatic tool-calling tool, backed by AI Gateway's sandboxed runtime. Declare the code_execution tool alongside your function tools; the proxy runs the sandbox, pauses for inner tool calls, and returns server_tool_use / code_execution_tool_result blocks in the Anthropic wire shape. Requires the code_executor feature on your organization.

tools[] entry
{ "type": "code_execution_20260120", "name": "code_execution" }

Custom function tools you want the sandbox to call declare allowed_callers (e.g. ["code_execution_20260120"]). The runtime, containers, file inputs/outputs and limits are shared with the Responses hosted tool — see Code Interpreter for the full behavior.

Prompt Vault

Reference a prompt stored in the Prompt Vault via the prompt extra-body field (the Anthropic API has no native stored-prompt param); messages becomes optional when the prompt provides the conversation. The gateway resolves and strips it before the request reaches the provider.

example.ts
import { anthropic } from "./client"; const message = await anthropic.messages.create({ model: "claude-sonnet-5", max_tokens: 1024, messages: [{ role: "user", content: "App keeps crashing on launch" }], // Caronte extension — the gateway resolves and strips it // @ts-expect-error not part of the Anthropic types prompt: { id: "support/triage", version: "production" }, });

tip · Merge semantics

With no client messages the compiled prompt becomes the conversation; with them, only the prompt's system part is merged (vault-first) and its user/assistant turns are dropped. Not supported on /count_tokens. Full cross-endpoint rules in Prompt Vault → Merge.

Counting tokens

POST /anthropic/v1/messages/count_tokens returns { input_tokens } for a request without running it. It is not a generation — no cost, no guardrails, no trace — but PII masking still applies to what would leave the gateway. max_tokens is not required here.

example.ts
import { anthropic } from "./client"; const { input_tokens } = await anthropic.messages.countTokens({ model: "claude-sonnet-5", messages: [{ role: "user", content: "How many tokens is this?" }], }); console.log(input_tokens);

Provider fidelity

What each dispatch path preserves. The native Anthropic path is a verbatim passthrough; other providers are translated Anthropic ⇄ their dialect and lose the features below.

FieldTypeDescription
anthropic (Claude, direct)nativeFull fidelity: cache_control, thinking + signatures, server tools and multi-turn thinking all pass through.
openai, azure-openaivia Responses APIFunction tools, images, streaming and reasoning effort supported. cache_control, stop_sequences and history thinking are dropped.
gemini, aws-bedrockvia Chat translationFunction tools, images and streaming supported; cache_control and history thinking dropped. Bedrock reasoning output is not surfaced (see Extended thinking).
Prompt Vaultextra-body fieldSupported on every provider path — pass the prompt reference via extra_body. Merge behavior is in the Prompt Vault section above.

Gateway features & headers

Everything the OpenAI endpoints get, in the Anthropic envelope.

  • Budgets, request caps & guardrails are enforced before the provider, exactly as on the OpenAI endpoints (over-limit → 429; warning headers ride on the response).
  • Tracing attaches via the same X-Trace-Id / X-Trace-Name / X-Generation-Name / X-Session-Id / X-Session-Name / X-User headers (or body metadata.user_id); X-No-Log skips payload storage.
  • PII masking rehydrates the response on non-streaming requests (rejected on streaming — see above), and request size is capped at 32 MB (inline base64 images count) → 413.

note · Errors use the Anthropic envelope

Failures return { "type": "error", "error": { "type", "message" } } with the matching status (401 authentication_error, 429 rate_limit_error, etc.). On a stream, a mid-stream failure arrives as a named error event.