curl --request POST \
--url https://openrouter.ai/api/v1/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"max_tokens": 1024,
"messages": [
{
"content": "Hello, how are you?",
"role": "user"
}
],
"model": "anthropic/claude-sonnet-4"
}
'import requests
url = "https://openrouter.ai/api/v1/messages"
payload = {
"max_tokens": 1024,
"messages": [
{
"content": "Hello, how are you?",
"role": "user"
}
],
"model": "anthropic/claude-sonnet-4"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
max_tokens: 1024,
messages: [{content: 'Hello, how are you?', role: 'user'}],
model: 'anthropic/claude-sonnet-4'
})
};
fetch('https://openrouter.ai/api/v1/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://openrouter.ai/api/v1/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'max_tokens' => 1024,
'messages' => [
[
'content' => 'Hello, how are you?',
'role' => 'user'
]
],
'model' => 'anthropic/claude-sonnet-4'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://openrouter.ai/api/v1/messages"
payload := strings.NewReader("{\n \"max_tokens\": 1024,\n \"messages\": [\n {\n \"content\": \"Hello, how are you?\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"anthropic/claude-sonnet-4\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://openrouter.ai/api/v1/messages")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"max_tokens\": 1024,\n \"messages\": [\n {\n \"content\": \"Hello, how are you?\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"anthropic/claude-sonnet-4\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://openrouter.ai/api/v1/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"max_tokens\": 1024,\n \"messages\": [\n {\n \"content\": \"Hello, how are you?\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"anthropic/claude-sonnet-4\"\n}"
response = http.request(request)
puts response.read_body{
"container": null,
"content": [
{
"citations": [],
"text": "I'm doing well, thank you for asking! How can I help you today?",
"type": "text"
}
],
"id": "msg_abc123",
"model": "anthropic/claude-sonnet-4",
"role": "assistant",
"stop_details": null,
"stop_reason": "end_turn",
"stop_sequence": null,
"type": "message",
"usage": {
"cache_creation": null,
"cache_creation_input_tokens": null,
"cache_read_input_tokens": null,
"inference_geo": null,
"input_tokens": 12,
"output_tokens": 18,
"output_tokens_details": null,
"server_tool_use": null,
"service_tier": "standard"
}
}Create a message
Creates a message using the Anthropic Messages API format. Supports text, images, PDFs, tools, and extended thinking.
curl --request POST \
--url https://openrouter.ai/api/v1/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"max_tokens": 1024,
"messages": [
{
"content": "Hello, how are you?",
"role": "user"
}
],
"model": "anthropic/claude-sonnet-4"
}
'import requests
url = "https://openrouter.ai/api/v1/messages"
payload = {
"max_tokens": 1024,
"messages": [
{
"content": "Hello, how are you?",
"role": "user"
}
],
"model": "anthropic/claude-sonnet-4"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
max_tokens: 1024,
messages: [{content: 'Hello, how are you?', role: 'user'}],
model: 'anthropic/claude-sonnet-4'
})
};
fetch('https://openrouter.ai/api/v1/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://openrouter.ai/api/v1/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'max_tokens' => 1024,
'messages' => [
[
'content' => 'Hello, how are you?',
'role' => 'user'
]
],
'model' => 'anthropic/claude-sonnet-4'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://openrouter.ai/api/v1/messages"
payload := strings.NewReader("{\n \"max_tokens\": 1024,\n \"messages\": [\n {\n \"content\": \"Hello, how are you?\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"anthropic/claude-sonnet-4\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://openrouter.ai/api/v1/messages")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"max_tokens\": 1024,\n \"messages\": [\n {\n \"content\": \"Hello, how are you?\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"anthropic/claude-sonnet-4\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://openrouter.ai/api/v1/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"max_tokens\": 1024,\n \"messages\": [\n {\n \"content\": \"Hello, how are you?\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"anthropic/claude-sonnet-4\"\n}"
response = http.request(request)
puts response.read_body{
"container": null,
"content": [
{
"citations": [],
"text": "I'm doing well, thank you for asking! How can I help you today?",
"type": "text"
}
],
"id": "msg_abc123",
"model": "anthropic/claude-sonnet-4",
"role": "assistant",
"stop_details": null,
"stop_reason": "end_turn",
"stop_sequence": null,
"type": "message",
"usage": {
"cache_creation": null,
"cache_creation_input_tokens": null,
"cache_read_input_tokens": null,
"inference_geo": null,
"input_tokens": 12,
"output_tokens": 18,
"output_tokens_details": null,
"server_tool_use": null,
"service_tier": "standard"
}
}Authorizations
API key as bearer token in Authorization header
Headers
Opt-in to surface routing metadata on the response under openrouter_metadata. Defaults to disabled. The legacy header X-OpenRouter-Experimental-Metadata is also accepted for backward compatibility.
Opt-in level for surfacing routing metadata on the response under openrouter_metadata.
disabled, enabled "enabled"
Body
Request schema for Anthropic Messages API endpoint
Show child attributes
Show child attributes
Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. When set on an individual content block, it marks an explicit cache breakpoint; block-level markers also work on OpenAI models that support explicit prompt caching — OpenRouter converts them to the provider's native format.
Show child attributes
Show child attributes
{ "type": "ephemeral" }
Show child attributes
Show child attributes
Fallback models to try if the primary model fails or refuses, in order. Handled by OpenRouter multi-model routing rather than Anthropic server-side fallbacks; cannot be combined with models. Each entry accepts only model. Maximum of 3 entries.
Show child attributes
Show child attributes
[{ "model": "claude-opus-4-8" }]
Show child attributes
Show child attributes
Configuration for controlling output behavior. Supports the effort parameter and structured output format.
Show child attributes
Show child attributes
{ "effort": "medium" }
Plugins you want to enable for this request, including their settings.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
- Option 8
- Option 9
- Option 10
Show child attributes
Show child attributes
{
"allowed_models": ["anthropic/*", "openai/*"],
"cost_tier": "low",
"enabled": true,
"excluded_models": ["openai/gpt-4o"],
"id": "auto-router",
"pin_model": false
}
When multiple model providers are available, optionally indicate your routing preference.
Show child attributes
Show child attributes
{ "allow_fallbacks": true }
DEPRECATED Use providers.sort.partition instead. Backwards-compatible alias for providers.sort.partition. Accepts legacy values: "fallback" (maps to "model"), "sort" (maps to "none").
fallback, sort, null "fallback"
A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters.
256Controls output generation speed. When set to fast, uses a higher-speed inference configuration at premium pricing. Defaults to standard when omitted.
fast, standard, null "fast"
Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides max_tool_calls. When a condition fires while the model is still emitting tool calls, the pending tool calls are executed and one final turn is made with tool calls disabled so the response ends with a natural-language answer instead of an unfinished tool call.
1A single condition that, when met, halts the server-tool agent loop.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
Show child attributes
Show child attributes
{ "step_count": 5, "type": "step_count_is" }
[
{ "step_count": 5, "type": "step_count_is" },
{
"max_cost_in_dollars": 0.5,
"type": "max_cost"
}
]
- Option 1
- Option 2
- Option 3
Show child attributes
Show child attributes
- Option 1
- Option 2
- Option 3
- Option 4
Show child attributes
Show child attributes
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
- Option 8
- Option 9
- Option 10
- Option 11
- Option 12
- Option 13
- Option 14
- Option 15
- Option 16
- Option 17
Show child attributes
Show child attributes
Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations.
Show child attributes
Show child attributes
{
"trace_id": "trace-abc123",
"trace_name": "my-app-trace"
}
A unique identifier representing your end-user, which helps distinguish between different users of your app. This allows your app to identify specific users in case of abuse reports, preventing your entire app from being affected by the actions of individual users. Maximum of 256 characters.
256Response
Successful response
Non-streaming response from the Anthropic Messages API with OpenRouter extensions
Show child attributes
Show child attributes
{
"expires_at": "2026-04-08T00:00:00Z",
"id": "ctr_01abc",
"skills": null
}
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
- Option 8
- Option 9
- Option 10
- Option 11
- Option 12
- Option 13
- Option 14
- Option 15
- Option 16
Show child attributes
Show child attributes
{
"citations": null,
"text": "Hello, world!",
"type": "text"
}
assistant Structured information about a refusal
Show child attributes
Show child attributes
{
"category": "cyber",
"explanation": "The request was refused due to policy.",
"type": "refusal"
}
end_turn, max_tokens, model_context_window_exceeded, stop_sequence, tool_use, pause_turn, refusal, compaction, null "end_turn"
message Show child attributes
Show child attributes
{
"cache_creation": null,
"cache_creation_input_tokens": null,
"cache_read_input_tokens": null,
"inference_geo": null,
"input_tokens": 100,
"output_tokens": 50,
"output_tokens_details": null,
"server_tool_use": null,
"service_tier": "standard"
}
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
{
"attempt": 1,
"endpoints": {
"available": [
{
"model": "openai/gpt-4o",
"provider": "OpenAI",
"selected": true
}
],
"total": 1
},
"generation_time": 2016,
"is_byok": false,
"region": "iad",
"requested": "openai/gpt-4o",
"strategy": "direct",
"summary": "available=1, selected=OpenAI"
}
Modal, AkashML, AI21, AionLabs, Alibaba, Ambient, Baidu, Amazon Bedrock, Amazon Nova, Anthropic, Arcee AI, AtlasCloud, Avian, Azure, BaseTen, BytePlus, Black Forest Labs, Cerebras, Chutes, Cirrascale, Claude Platform on AWS, Clarifai, Cloudflare, Cohere, CoreWeave, Cosine, Crucible, Crusoe, Darkbloom, Databricks, Decart, Deepgram, DeepInfra, DeepSeek, DekaLLM, DigitalOcean, Featherless, Fireworks, Fish Audio, Friendli, GMICloud, Google, Google AI Studio, Groq, HeyGen, Inception, Inceptron, InferenceNet, Ionstream, Infermatic, Io Net, Inferact vLLM, Inflection, Liquid, Makora, Mara, Mancer 2, Meta, Minimax, ModelRun, Mistral, Modular, Moonshot AI, Morph, VoyageAI by MongoDB, NCompass, Nebius, Nex AGI, NextBit, Novita, Nvidia, Ollama, OpenAI, OpenInference, Parasail, Poolside, Perceptron, Perplexity, Phala, Recraft, Reka, Relace, Sail Research, Sakana AI, SambaNova, Seed, SiliconFlow, Sourceful, StepFun, Stealth, StreamLake, Switchpoint, Tencent, Tenstorrent, Thinking Machines, Together, Upstage, Venice, Wafer, WandB, Quiver, Krea, Runway, Xiaomi, xAI, Z.AI, FakeProvider "OpenAI"