How to Use the Anthropic Messages API with Claude Clients in FreeLLMAPI

FreeLLMAPI implements a fully compatible Anthropic Messages API endpoint at POST /v1/messages in server/src/routes/anthropic.ts that authenticates requests via the x-api-key header, translates Anthropic-formatted payloads into an internal OpenAI-shaped format for unified routing, and converts provider responses back to Anthropic's wire protocol.

FreeLLMAPI exposes the Anthropic Messages API to enable Claude-based clients (such as Claude Code) to connect to its free model routing infrastructure. The implementation acts as a thin adapter layer that validates Anthropic-specific request envelopes while leveraging the same retry, fallback, and analytics machinery used for OpenAI-compatible endpoints.

Authentication and Request Validation

Validating Anthropic API Keys

The route accepts authentication via the Anthropic-standard x-api-key header or a bearer token. In server/src/routes/anthropic.ts, the authenticate() function (lines 27-33) validates the provided key against the unified API key stored in the database. If the key is missing or invalid, the endpoint returns a 401 authentication_error response immediately.

Schema Validation with Zod

Incoming requests are validated using a Zod schema defined in messagesSchema (lines 48-89). The schema permissively validates required fields including messages, max_tokens, and tools while using .passthrough() to allow unknown fields. This design ensures forward compatibility with future Anthropic content block types without requiring immediate code changes.

Request Translation and Model Routing

Converting to Internal Format

The convertRequest() function (lines 94-184) translates the incoming Anthropic request into the internal ChatMessage[] format used by the router. This conversion includes flattening any system turn into a system message, extracting text and image blocks, and converting Anthropic tool-use structures into internal ChatToolCall and ChatMessage objects. The function also maps the Anthropic tool_choice enum to the OpenAI ChatToolChoice format expected by the routing layer.

Model Resolution and Auto-Routing

Model resolution occurs via services/anthropic-map.ts. When the request specifies model: 'auto' or omits the model entirely, the resolveAnthropicModel() call (lines 66-68) triggers automatic selection of an available free model from the catalog. If a specific Claude model identifier is provided (e.g., claude-3-sonnet-20240229), the system attempts to route to that pinned model or a compatible alternative based on current rate limits.

Session Affinity for Claude Code

To prevent model "flapping" during multi-turn conversations, the route inspects the X-Claude-Code-Session-Id or generic X-Session-Id headers. The session handling logic (lines 70-77) uses setStickyModel and getStickyModel to remember the chosen model for the duration of the session, ensuring consistent provider selection across related requests.

Streaming and Response Handling

SSE Streaming Support

When stream: true is set in the request, the route delegates to streamCompletion() (lines 98-137). This helper consumes the OpenAI-style stream from the selected provider and re-emits it as an Anthropic-compliant Server-Sent Events (SSE) sequence, including events such as message_start, content_block_delta, and message_stop. The streaming implementation maintains the same retry logic as non-streaming requests, with MAX_RETRIES set to 20 for automatic failover.

Mapping Responses Back to Anthropic Format

After receiving a provider response, the system translates internal ChatMessage objects back to Anthropic's wire format. The toAnthropicContent() function (lines 11-19) constructs the response content array from text and tool calls, while mapStopReason() (lines 100-105) converts OpenAI finish reasons (like stop or length) to Anthropic stop_reason values (such as end_turn or max_tokens).

Error Handling and Analytics

The route implements comprehensive error handling through sanitized error messages. Provider errors are processed via sanitizeProviderErrorMessage from lib/error-redaction.ts, logged through logRequest, and converted to Anthropic-compatible error payloads via sendError. The error handling sections (lines 55-78 and 150-170) distinguish between retryable errors (triggering cooldown and fallback) and fatal errors (returning immediately to the client). Rate-limit hits and model-not-found cases automatically increment fallback counters and select alternative providers.

Auxiliary Endpoints

Token Counting

The auxiliary endpoint POST /v1/messages/count_tokens (lines 390-399) provides token estimation without invoking an actual provider. It reuses the same request translation logic to calculate usage statistics for budget planning and client-side validation.

Model Listing

The GET /v1/models endpoint (lines 514-576) returns the unified model catalog when the request includes an anthropic-version header. This allows Claude-compatible clients to discover available models through the standard Anthropic API surface.

Implementation Examples

Below are minimal examples demonstrating how to call the FreeLLMAPI Anthropic endpoint from a Node.js environment.

Non-Streaming Request

const response = await fetch('https://YOUR_FREELLMAPI_HOST/anthropic/v1/messages', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'YOUR_UNIFIED_API_KEY',
    'anthropic-version': '2023-06-01',
  },
  body: JSON.stringify({
    model: 'claude-3-sonnet-20240229',
    max_tokens: 1024,
    messages: [{ role: 'user', content: 'Hello, Claude!' }],
  }),
});

const result = await response.json();
console.log(result.content);

Streaming Request

const res = await fetch('https://YOUR_FREELLMAPI_HOST/anthropic/v1/messages', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'YOUR_UNIFIED_API_KEY',
    'anthropic-version': '2023-06-01',
  },
  body: JSON.stringify({
    model: 'auto',
    max_tokens: 1024,
    stream: true,
    messages: [{ role: 'user', content: 'Tell me a short story.' }],
  }),
});

const reader = res.body?.getReader();
while (true) {
  const { done, value } = await reader!.read();
  if (done) break;
  const chunk = new TextDecoder().decode(value);
  console.log(chunk); // SSE formatted events
}

Both examples target the /anthropic/v1/messages path and automatically benefit from the retry logic, session affinity, and model fallback implemented in server/src/routes/anthropic.ts.

Summary

  • Unified Authentication: The Anthropic Messages API uses the same API keys as OpenAI routes, validated in authenticate() at lines 27-33 of server/src/routes/anthropic.ts.
  • Format Translation: convertRequest() maps Anthropic payloads to internal OpenAI shapes, enabling shared routing logic across provider types.
  • Automatic Failover: Up to 20 retries with cooldown management and model fallback ensure high availability when using model: 'auto'.
  • Session Consistency: The X-Claude-Code-Session-Id header triggers sticky model selection to prevent mid-conversation provider switches.
  • Full Streaming: SSE streams are translated in real-time by streamCompletion() while preserving Anthropic event semantics.
  • Auxiliary Support: Token counting and model listing endpoints provide complete API compatibility for Claude clients.

Frequently Asked Questions

How do I authenticate with the FreeLLMAPI Anthropic Messages API?

Authentication uses the unified API key system. Send your API key in the x-api-key header (or as a bearer token) exactly as you would for OpenAI endpoints. The authenticate() function in server/src/routes/anthropic.ts validates this against the database at lines 27-33.

Can I use Claude Code with FreeLLMAPI?

Yes. Configure Claude Code to point to your FreeLLMAPI host and provide the anthropic-version header (e.g., 2023-06-01). The route specifically handles X-Claude-Code-Session-Id headers (lines 70-77) to maintain session affinity and prevent model switching mid-conversation.

What happens if the requested Claude model is unavailable?

If you specify model: 'auto' or omit the model field, the system automatically selects a free available model via resolveAnthropicModel(). If you request a specific model that hits rate limits, the retry loop (lines 82-125) attempts up to 20 alternative providers before returning an error.

Does the endpoint support tool use and function calling?

Yes. The Zod schema at lines 48-89 validates tools and tool_choice parameters, while convertRequest() translates Anthropic tool blocks into internal ChatToolCall structures. Tool results are similarly mapped back to Anthropic's expected response format in toAnthropicContent().

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →