Skip to content

Anthropic Messages API

Apex AI Proxy provides full compatibility with Anthropic's Messages API, allowing you to use Claude Code, Anthropic SDK, and other Anthropic-compatible tools with any configured provider. The proxy automatically converts between Anthropic and OpenAI formats.

Endpoint

POST /v1/messages

Authentication

All requests require authentication using one of these methods:

http
# Standard Authorization header
Authorization: Bearer your-service-api-key

# Anthropic-style header (also supported)
x-api-key: your-service-api-key

Request Format

Basic Request

json
{
  "model": "claude-3-sonnet",
  "max_tokens": 100,
  "messages": [
    {
      "role": "user",
      "content": "Hello, Claude!"
    }
  ]
}

Complete Request Example

json
{
  "model": "claude-3-sonnet",
  "max_tokens": 1000,
  "system": "You are a helpful assistant specialized in Python programming.",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Write a Python function to calculate fibonacci numbers"
        }
      ]
    }
  ],
  "temperature": 0.7,
  "top_p": 0.9,
  "stop_sequences": ["```", "---"],
  "stream": false
}

Request Parameters

ParameterTypeRequiredDescription
modelstringModel to use (configured in your proxy)
max_tokensintegerMaximum tokens to generate
messagesarrayArray of message objects
systemstring/arraySystem message or array of system messages
temperaturenumberSampling temperature (0.0-2.0)
top_pnumberNucleus sampling parameter
stop_sequencesarrayCustom stop sequences
streambooleanEnable streaming responses
toolsarrayAvailable tools for function calling
tool_choiceobjectTool selection preference

Model Configuration

The proxy maps Anthropic model names to your configured providers:

javascript
// Example configuration in wrangler-config.js
const modelProviderConfig = {
  'claude-3-sonnet': {
    providers: [
      { provider: 'deepseek', model: 'deepseek-chat' },
      { provider: 'azure', model: 'gpt-4' },
    ],
  },
  'claude-3-opus': {
    providers: [
      { provider: 'azure', model: 'gpt-4' },
    ],
  },
  'claude-3-haiku': {
    providers: [
      { provider: 'deepseek', model: 'deepseek-chat' },
    ],
  },
};

System Messages

System messages can be provided as a string or array:

json
{
  "system": "You are a helpful assistant."
}
json
{
  "system": [
    {
      "type": "text",
      "text": "You are a helpful assistant."
    },
    {
      "type": "text", 
      "text": "Always respond in a friendly tone."
    }
  ]
}

Message Content

Messages support both simple text and structured content:

Simple Text

json
{
  "role": "user",
  "content": "What is the capital of France?"
}

Structured Content

json
{
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": "Analyze this code:"
    },
    {
      "type": "text",
      "text": "```python\ndef hello():\n    print('Hello, world!')\n```"
    }
  ]
}

Response Format

Successful Response

json
{
  "id": "msg_abc123",
  "type": "message",
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "Hello! I'm Claude, an AI assistant. How can I help you today?"
    }
  ],
  "model": "claude-3-sonnet",
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 12,
    "output_tokens": 19
  }
}

Response Fields

FieldTypeDescription
idstringUnique message identifier
typestringAlways "message"
rolestringAlways "assistant"
contentarrayArray of content blocks
modelstringModel used for generation
stop_reasonstringReason completion stopped
stop_sequencestringStop sequence that triggered end
usageobjectToken usage statistics

Stop Reasons

ReasonDescription
end_turnNatural end of response
max_tokensReached token limit
stop_sequenceHit a stop sequence
tool_useModel wants to use a tool

Streaming Responses

Enable real-time streaming by setting stream: true:

Request

json
{
  "model": "claude-3-sonnet",
  "max_tokens": 100,
  "messages": [
    {
      "role": "user",
      "content": "Tell me a story"
    }
  ],
  "stream": true
}

Streaming Events

The proxy returns Server-Sent Events following Anthropic's format:

event: message_start
data: {"type":"message_start","message":{"id":"msg_abc123","type":"message","role":"assistant","content":[],"model":"claude-3-sonnet","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":12,"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":"Once"}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" upon"}}

event: content_block_stop
data: {"type":"content_block_stop","index":0}

event: message_stop
data: {"type":"message_stop"}

Tool Usage (Function Calling)

The proxy supports Anthropic's tool use format with automatic conversion to OpenAI function calling:

Tool Definition

json
{
  "model": "claude-3-sonnet",
  "max_tokens": 100,
  "tools": [
    {
      "name": "get_weather",
      "description": "Get weather information for a location",
      "input_schema": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "City name"
          },
          "unit": {
            "type": "string",
            "enum": ["celsius", "fahrenheit"],
            "description": "Temperature unit"
          }
        },
        "required": ["location"]
      }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": "What's the weather in Paris?"
    }
  ]
}

Tool Choice Options

json
{
  "tool_choice": {"type": "auto"}        // Let model decide
}
json
{
  "tool_choice": {"type": "any"}         // Must use a tool
}
json
{
  "tool_choice": {                       // Use specific tool
    "type": "tool",
    "name": "get_weather"
  }
}
json
{
  "tool_choice": {"type": "none"}        // Don't use tools
}

Tool Use Response

json
{
  "id": "msg_abc123",
  "type": "message",
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "I'll check the weather in Paris for you."
    },
    {
      "type": "tool_use",
      "id": "toolu_abc123",
      "name": "get_weather",
      "input": {
        "location": "Paris",
        "unit": "celsius"
      }
    }
  ],
  "model": "claude-3-sonnet",
  "stop_reason": "tool_use",
  "usage": {
    "input_tokens": 25,
    "output_tokens": 45
  }
}

Tool Result

Provide tool results in follow-up messages:

json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_abc123",
      "content": "The weather in Paris is 22°C and sunny."
    }
  ]
}

Code Examples

Python (Anthropic SDK)

python
import anthropic

client = anthropic.Anthropic(
    base_url="https://your-proxy.workers.dev",
    api_key="your-service-api-key"
)

# Basic message
message = client.messages.create(
    model="claude-3-sonnet",
    max_tokens=100,
    messages=[
        {
            "role": "user",
            "content": "Hello, Claude!"
        }
    ]
)

print(message.content[0].text)

# Streaming message
stream = client.messages.create(
    model="claude-3-sonnet",
    max_tokens=100,
    messages=[
        {
            "role": "user",
            "content": "Tell me a joke"
        }
    ],
    stream=True
)

for event in stream:
    if event.type == "content_block_delta":
        print(event.delta.text, end="")

JavaScript/Node.js

javascript
import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic({
  baseURL: 'https://your-proxy.workers.dev',
  apiKey: 'your-service-api-key',
});

// Basic message
const message = await anthropic.messages.create({
  model: 'claude-3-sonnet',
  max_tokens: 100,
  messages: [
    {
      role: 'user',
      content: 'Hello, Claude!'
    }
  ]
});

console.log(message.content[0].text);

// Streaming message
const stream = anthropic.messages.stream({
  model: 'claude-3-sonnet',
  max_tokens: 100,
  messages: [
    {
      role: 'user',
      content: 'Count from 1 to 10'
    }
  ]
});

stream.on('text', (text) => {
  process.stdout.write(text);
});

curl

bash
# Basic message
curl -X POST https://your-proxy.workers.dev/v1/messages \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-service-api-key" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-3-sonnet",
    "max_tokens": 100,
    "messages": [
      {
        "role": "user",
        "content": "Hello, Claude!"
      }
    ]
  }'

# Streaming message
curl -X POST https://your-proxy.workers.dev/v1/messages \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-service-api-key" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-3-sonnet",
    "max_tokens": 100,
    "stream": true,
    "messages": [
      {
        "role": "user",
        "content": "Tell me about AI"
      }
    ]
  }'

Claude Code Integration

Use with Claude Code (Anthropic's VS Code extension):

Environment Setup

bash
# Set environment variables
export ANTHROPIC_BASE_URL=https://your-proxy.workers.dev
export ANTHROPIC_AUTH_TOKEN=your-service-api-key
export API_TIMEOUT_MS=600000
export ANTHROPIC_MODEL=claude-3-sonnet
export ANTHROPIC_SMALL_FAST_MODEL=claude-3-haiku

Usage

bash
# Navigate to your project
cd /path/to/your/project

# Start Claude Code
claude

# Now you can chat with Claude using your proxy

Advanced Features

Multi-turn Conversations

json
{
  "model": "claude-3-sonnet",
  "max_tokens": 200,
  "messages": [
    {
      "role": "user",
      "content": "What is Python?"
    },
    {
      "role": "assistant", 
      "content": "Python is a high-level programming language..."
    },
    {
      "role": "user",
      "content": "Show me a simple example"
    }
  ]
}

Complex Tool Usage

python
# Tool with multiple parameters
tools = [
    {
        "name": "search_database",
        "description": "Search for information in the database",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "table": {"type": "string", "enum": ["users", "products", "orders"]},
                "limit": {"type": "integer", "minimum": 1, "maximum": 100}
            },
            "required": ["query", "table"]
        }
    }
]

Custom Stop Sequences

json
{
  "model": "claude-3-sonnet",
  "max_tokens": 500,
  "stop_sequences": ["```", "---", "END"],
  "messages": [
    {
      "role": "user",
      "content": "Write code and stop at the first ```"
    }
  ]
}

Error Handling

Common Errors

json
{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "max_tokens is required"
  }
}

Error Types

Error TypeDescription
invalid_request_errorInvalid request parameters
authentication_errorInvalid API key
permission_errorInsufficient permissions
not_found_errorModel or resource not found
rate_limit_errorRate limit exceeded
api_errorInternal API error
overloaded_errorService temporarily overloaded

Error Handling Example

python
import anthropic

client = anthropic.Anthropic(
    base_url="https://your-proxy.workers.dev",
    api_key="your-service-api-key"
)

try:
    message = client.messages.create(
        model="claude-3-sonnet",
        max_tokens=100,
        messages=[
            {"role": "user", "content": "Hello!"}
        ]
    )
    print(message.content[0].text)
except anthropic.RateLimitError:
    print("Rate limit exceeded")
except anthropic.APIError as e:
    print(f"API error: {e}")

Protocol Conversion

The proxy automatically handles conversion between Anthropic and OpenAI formats:

Anthropic → OpenAI Conversion

Anthropic FieldOpenAI FieldNotes
max_tokensmax_tokensDirect mapping
systemmessages[0]Added as system message
stop_sequencesstopArray converted to OpenAI format
toolsfunctionsSchema cleaned for compatibility
tool_choicefunction_callType conversion applied

OpenAI → Anthropic Response

OpenAI FieldAnthropic FieldNotes
choices[0].messagecontentConverted to content blocks
usageusageToken counts mapped
finish_reasonstop_reasonReason mapping applied

Compatibility Matrix

FeatureSupport StatusNotes
Basic Messages✅ FullComplete message support
System Messages✅ FullString and array formats
Streaming✅ FullAll event types supported
Tool Use✅ FullFunction calling with conversion
Stop Sequences✅ FullCustom stop sequences
Temperature✅ FullRange 0.0-2.0
Top P✅ FullNucleus sampling
Top K❌ IgnoredNot supported by OpenAI providers
Image Content❌ Not SupportedRequires provider-specific implementation

Best Practices

1. Model Selection

Configure appropriate model mappings:

javascript
const modelProviderConfig = {
  // Fast model for simple tasks
  'claude-3-haiku': {
    providers: [
      { provider: 'deepseek', model: 'deepseek-chat' }
    ]
  },
  
  // Balanced model for most tasks
  'claude-3-sonnet': {
    providers: [
      { provider: 'azure', model: 'gpt-4' },
      { provider: 'deepseek', model: 'deepseek-chat' }
    ]
  },
  
  // Powerful model for complex tasks
  'claude-3-opus': {
    providers: [
      { provider: 'azure', model: 'gpt-4' }
    ]
  }
};

2. System Message Usage

Use system messages effectively:

json
{
  "system": "You are Claude, an AI assistant created by Anthropic. You are helpful, harmless, and honest.",
  "messages": [...]
}

3. Tool Schema Design

Keep tool schemas simple and clean:

json
{
  "name": "calculate",
  "description": "Perform mathematical calculations",
  "input_schema": {
    "type": "object",
    "properties": {
      "expression": {
        "type": "string",
        "description": "Mathematical expression to evaluate"
      }
    },
    "required": ["expression"]
  }
}

4. Error Recovery

Implement proper retry logic:

python
import time
import anthropic

def send_message_with_retry(client, **kwargs):
    max_retries = 3
    for attempt in range(max_retries):
        try:
            return client.messages.create(**kwargs)
        except anthropic.RateLimitError:
            if attempt < max_retries - 1:
                time.sleep(2 ** attempt)
            else:
                raise

Next Steps

External Resources

Released under the MIT License.