Portkey’s /v1/messages endpoint accepts the Anthropic Messages API format and routes to any of 3000+ models across all major providers. Tools built natively on the Messages format — like Claude Code and the Claude Agent SDK — work with any backend model through Portkey without modification.
The SDK code, request format, and response shape are identical across all providers. Portkey translates the Messages format to each provider’s native API. See Provider Support for how this works.
Already using the Anthropic SDK? Point it at Portkey:
Python
client = anthropic.Anthropic( api_key="PORTKEY_API_KEY", # Replace your Anthropic key with your Portkey API key base_url="https://api.portkey.ai" # Point at Portkey)
All existing Messages API calls work as-is. Use the @anthropic-provider/ prefix to keep routing to Anthropic, or switch the model string to any other provider.
The system parameter also accepts an array of content blocks for prompt caching:
Python
message = client.messages.create( model="@anthropic-provider/claude-sonnet-4-5-20250514", max_tokens=1024, system=[ {"type": "text", "text": "You are an expert on this topic..."}, {"type": "text", "text": "Here is the reference material...", "cache_control": {"type": "ephemeral"}} ], messages=[{"role": "user", "content": "Summarize the key points"}])
Stream responses with stream=True in the SDK or "stream": true in cURL.
with client.messages.stream( model="@anthropic-provider/claude-sonnet-4-5-20250514", max_tokens=1024, messages=[{"role": "user", "content": "Write a haiku about AI"}]) as stream: for text in stream.text_stream: print(text, end="", flush=True)
const stream = client.messages.stream({ model: "@anthropic-provider/claude-sonnet-4-5-20250514", max_tokens: 1024, messages: [{ role: "user", content: "Write a haiku about AI" }]});for await (const event of stream) { if (event.type === "content_block_delta" && event.delta.type === "text_delta") { process.stdout.write(event.delta.text); }}
Build conversations by passing the full message history. Messages must alternate between user and assistant roles.
message = client.messages.create( model="@anthropic-provider/claude-sonnet-4-5-20250514", max_tokens=1024, messages=[ {"role": "user", "content": "My name is Alice."}, {"role": "assistant", "content": "Hello Alice! How can I help you?"}, {"role": "user", "content": "What is my name?"} ])print(message.content[0].text) # "Your name is Alice."
const message = await client.messages.create({ model: "@anthropic-provider/claude-sonnet-4-5-20250514", max_tokens: 1024, messages: [ { role: "user", content: "My name is Alice." }, { role: "assistant", content: "Hello Alice! How can I help you?" }, { role: "user", content: "What is my name?" } ]});console.log(message.content[0].text);
curl https://api.portkey.ai/v1/messages \ -H "Content-Type: application/json" \ -H "x-portkey-api-key: $PORTKEY_API_KEY" \ -d '{ "model": "@anthropic-provider/claude-sonnet-4-5-20250514", "max_tokens": 1024, "messages": [ {"role": "user", "content": "My name is Alice."}, {"role": "assistant", "content": "Hello Alice! How can I help you?"}, {"role": "user", "content": "What is my name?"} ] }'
Two mechanisms for controlling model reasoning:thinking — Anthropic native. Pass directly to Anthropic Claude models. Silently dropped on adapter providers.output_config.effort — Cross-provider. Works across Anthropic, OpenAI o-series, and Gemini 2.5. Portkey maps it to each provider’s native reasoning format.
message = client.messages.create( model="@anthropic-provider/claude-sonnet-4-5-20250514", max_tokens=16000, thinking={"type": "enabled", "budget_tokens": 10000}, messages=[{"role": "user", "content": "Analyze the implications of quantum computing on cryptography"}])for block in message.content: if block.type == "thinking": print(f"Thinking: {block.thinking[:200]}...") elif block.type == "text": print(f"Response: {block.text}")
# Works with Anthropic, OpenAI o-series, Gemini 2.5message = client.messages.create( model="@openai-provider/o4-mini", max_tokens=4096, messages=[{"role": "user", "content": "Analyze the implications of quantum computing on cryptography"}], extra_body={"output_config": {"effort": "high"}})
const message = await (client.messages.create as any)({ model: "@openai-provider/o4-mini", max_tokens: 4096, messages: [{ role: "user", content: "Analyze the implications of quantum computing on cryptography" }], output_config: { effort: "high" }});
When using Anthropic’s thinking parameter, max_tokens must exceed budget_tokens. See Thinking Mode for provider-specific effort mappings.
Use cache_control on system prompts, messages, and tool definitions to cache frequently-used content.
message = client.messages.create( model="@anthropic-provider/claude-sonnet-4-5-20250514", max_tokens=1024, system=[{ "type": "text", "text": "You are an expert analyst. Here is a very long reference document...", "cache_control": {"type": "ephemeral"} }], messages=[{"role": "user", "content": "Summarize the key points"}])
message = client.messages.create( model="@anthropic-provider/claude-sonnet-4-5-20250514", max_tokens=1024, messages=[{ "role": "user", "content": [ {"type": "text", "text": "Here is a long document to analyze...", "cache_control": {"type": "ephemeral"}}, {"type": "text", "text": "What are the key themes?"} ] }])
Portkey handles the Messages API in two ways depending on the provider:
Native providers — Requests pass through directly. All Anthropic-specific features work (thinking, cache_control, top_k, etc.).
Adapter providers — Portkey translates between Messages format and the provider’s native Chat Completions format. See Parameter Compatibility for what is and isn’t supported.
The response always comes back in Anthropic Messages format, regardless of which provider handles the request.Native providers: Anthropic, AWS Bedrock (Claude models)Adapter providers: OpenAI, Azure OpenAI, Google Gemini, Google Vertex AI, AWS Bedrock (non-Claude), Mistral AI, Groq, Together AI, and all other providers
Portkey’s Messages adapter translates requests to each provider’s Chat Completions format for non-native providers.Unsupported parameters are silently dropped — no error is returned.Parameters translated for adapter providers:
Messages API param
Adapter equivalent
Notes
max_tokens
max_completion_tokens
stop_sequences
stop
system
First message with role: "system"
String or array both handled
tools[].input_schema
tools[].function.parameters
Format converted
tool_choice: {type: "auto"}
"auto"
tool_choice: {type: "any"}
"required"
tool_choice: {type: "tool", name: X}
{type: "function", function: {name: X}}
metadata.user_id
user
temperature, top_p, stream
Direct pass-through
output_config.format (json_schema)
response_format
Portkey extension; json_object not supported
output_config.effort
reasoning_effort
Portkey extension for cross-provider reasoning
Parameters silently dropped on adapter providers:
thinking — Anthropic-native; use output_config.effort for cross-provider reasoning control
top_k — no Chat Completions equivalent
cache_control — stripped during message transformation
Provider-specific parameters (e.g. Gemini’s safety_settings, Bedrock guardrail configs) cannot be passed through the Messages adapter. Use the provider’s native integration or Chat Completions instead.