Native Claude Format
curl --request POST \
--url https://api.gravitex.ai/v1/messages \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"messages": [
{}
],
"max_tokens": 123,
"system": {},
"temperature": 123,
"top_p": 123,
"top_k": 123,
"stream": true,
"stop_sequences": [
{}
],
"tools": [
{}
],
"tool_choice": {},
"thinking": {},
"output_config": {},
"metadata": {},
"mcp_servers": [
{}
],
"context_management": {},
"cache_control": {}
}
'import requests
url = "https://api.gravitex.ai/v1/messages"
payload = {
"model": "<string>",
"messages": [{}],
"max_tokens": 123,
"system": {},
"temperature": 123,
"top_p": 123,
"top_k": 123,
"stream": True,
"stop_sequences": [{}],
"tools": [{}],
"tool_choice": {},
"thinking": {},
"output_config": {},
"metadata": {},
"mcp_servers": [{}],
"context_management": {},
"cache_control": {}
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
messages: [{}],
max_tokens: 123,
system: {},
temperature: 123,
top_p: 123,
top_k: 123,
stream: true,
stop_sequences: [{}],
tools: [{}],
tool_choice: {},
thinking: {},
output_config: {},
metadata: {},
mcp_servers: [{}],
context_management: {},
cache_control: {}
})
};
fetch('https://api.gravitex.ai/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://api.gravitex.ai/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([
'model' => '<string>',
'messages' => [
[
]
],
'max_tokens' => 123,
'system' => [
],
'temperature' => 123,
'top_p' => 123,
'top_k' => 123,
'stream' => true,
'stop_sequences' => [
[
]
],
'tools' => [
[
]
],
'tool_choice' => [
],
'thinking' => [
],
'output_config' => [
],
'metadata' => [
],
'mcp_servers' => [
[
]
],
'context_management' => [
],
'cache_control' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"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://api.gravitex.ai/v1/messages"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"max_tokens\": 123,\n \"system\": {},\n \"temperature\": 123,\n \"top_p\": 123,\n \"top_k\": 123,\n \"stream\": true,\n \"stop_sequences\": [\n {}\n ],\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"thinking\": {},\n \"output_config\": {},\n \"metadata\": {},\n \"mcp_servers\": [\n {}\n ],\n \"context_management\": {},\n \"cache_control\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
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://api.gravitex.ai/v1/messages")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"max_tokens\": 123,\n \"system\": {},\n \"temperature\": 123,\n \"top_p\": 123,\n \"top_k\": 123,\n \"stream\": true,\n \"stop_sequences\": [\n {}\n ],\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"thinking\": {},\n \"output_config\": {},\n \"metadata\": {},\n \"mcp_servers\": [\n {}\n ],\n \"context_management\": {},\n \"cache_control\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gravitex.ai/v1/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"max_tokens\": 123,\n \"system\": {},\n \"temperature\": 123,\n \"top_p\": 123,\n \"top_k\": 123,\n \"stream\": true,\n \"stop_sequences\": [\n {}\n ],\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"thinking\": {},\n \"output_config\": {},\n \"metadata\": {},\n \"mcp_servers\": [\n {}\n ],\n \"context_management\": {},\n \"cache_control\": {}\n}"
response = http.request(request)
puts response.read_body{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Artificial intelligence is a branch of computer science that focuses on creating intelligent machines capable of performing tasks that typically require human intelligence..."
}
],
"model": "claude-sonnet-4-5-20250929",
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 25,
"output_tokens": 100
}
}
Chat & text
Native Claude Format
POST
/
v1
/
messages
Native Claude Format
curl --request POST \
--url https://api.gravitex.ai/v1/messages \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"messages": [
{}
],
"max_tokens": 123,
"system": {},
"temperature": 123,
"top_p": 123,
"top_k": 123,
"stream": true,
"stop_sequences": [
{}
],
"tools": [
{}
],
"tool_choice": {},
"thinking": {},
"output_config": {},
"metadata": {},
"mcp_servers": [
{}
],
"context_management": {},
"cache_control": {}
}
'import requests
url = "https://api.gravitex.ai/v1/messages"
payload = {
"model": "<string>",
"messages": [{}],
"max_tokens": 123,
"system": {},
"temperature": 123,
"top_p": 123,
"top_k": 123,
"stream": True,
"stop_sequences": [{}],
"tools": [{}],
"tool_choice": {},
"thinking": {},
"output_config": {},
"metadata": {},
"mcp_servers": [{}],
"context_management": {},
"cache_control": {}
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
messages: [{}],
max_tokens: 123,
system: {},
temperature: 123,
top_p: 123,
top_k: 123,
stream: true,
stop_sequences: [{}],
tools: [{}],
tool_choice: {},
thinking: {},
output_config: {},
metadata: {},
mcp_servers: [{}],
context_management: {},
cache_control: {}
})
};
fetch('https://api.gravitex.ai/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://api.gravitex.ai/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([
'model' => '<string>',
'messages' => [
[
]
],
'max_tokens' => 123,
'system' => [
],
'temperature' => 123,
'top_p' => 123,
'top_k' => 123,
'stream' => true,
'stop_sequences' => [
[
]
],
'tools' => [
[
]
],
'tool_choice' => [
],
'thinking' => [
],
'output_config' => [
],
'metadata' => [
],
'mcp_servers' => [
[
]
],
'context_management' => [
],
'cache_control' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"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://api.gravitex.ai/v1/messages"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"max_tokens\": 123,\n \"system\": {},\n \"temperature\": 123,\n \"top_p\": 123,\n \"top_k\": 123,\n \"stream\": true,\n \"stop_sequences\": [\n {}\n ],\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"thinking\": {},\n \"output_config\": {},\n \"metadata\": {},\n \"mcp_servers\": [\n {}\n ],\n \"context_management\": {},\n \"cache_control\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
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://api.gravitex.ai/v1/messages")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"max_tokens\": 123,\n \"system\": {},\n \"temperature\": 123,\n \"top_p\": 123,\n \"top_k\": 123,\n \"stream\": true,\n \"stop_sequences\": [\n {}\n ],\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"thinking\": {},\n \"output_config\": {},\n \"metadata\": {},\n \"mcp_servers\": [\n {}\n ],\n \"context_management\": {},\n \"cache_control\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gravitex.ai/v1/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"messages\": [\n {}\n ],\n \"max_tokens\": 123,\n \"system\": {},\n \"temperature\": 123,\n \"top_p\": 123,\n \"top_k\": 123,\n \"stream\": true,\n \"stop_sequences\": [\n {}\n ],\n \"tools\": [\n {}\n ],\n \"tool_choice\": {},\n \"thinking\": {},\n \"output_config\": {},\n \"metadata\": {},\n \"mcp_servers\": [\n {}\n ],\n \"context_management\": {},\n \"cache_control\": {}\n}"
response = http.request(request)
puts response.read_body{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Artificial intelligence is a branch of computer science that focuses on creating intelligent machines capable of performing tasks that typically require human intelligence..."
}
],
"model": "claude-sonnet-4-5-20250929",
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 25,
"output_tokens": 100
}
}
Introduction
Claudeโs native message API, suitable for native Anthropic clients like Claude Code. This API follows Anthropicโs specification and provides full Claude model capabilities, including Extended Thinking, tool calling, and other advanced features.If youโre using an OpenAI-compatible client (like OpenAI SDK), we recommend using the
/v1/chat/completions endpoint instead.Authentication
string
required
Bearer Token, e.g.,
Bearer sk-xxxxxxxxxxRequest Parameters
string
required
Claude model identifier, supported models include:
claude-fable-5- Claude Fable 5 (Latest, most capable)claude-opus-5- Claude Opus 5 (Latest, complex agentic and coding work)claude-sonnet-5- Claude Sonnet 5 (Best balance of speed and intelligence)claude-opus-4-8- Claude Opus 4.8claude-opus-4-7- Claude Opus 4.7claude-opus-4-6- Claude Opus 4.6claude-sonnet-4-6- Claude Sonnet 4.6 (Balanced performance)claude-opus-4-5-20251101- Claude Opus 4.5claude-haiku-4-5-20251001- Claude Haiku 4.5 (Fastest)claude-sonnet-4-5-20250929- Claude Sonnet 4.5claude-sonnet-4-20250514- Claude Sonnet 4- Other Claude series models
array
required
List of conversation messages, each containing
role (user/assistant) and content. content can be a string or an array of media content.number
required
Maximum number of tokens to generate. Must be greater than 0.
string|array
System prompt, can be a string or an array of media content. Used to set the modelโs behavior and role.
number
default:"1.0"
Randomness control, 0-1. Higher values make responses more random. Recommended to set to 1.0 when using extended thinking.
number
default:"1.0"
Nucleus sampling parameter, 0-1, controls generation diversity. Recommended to set to 0 when using extended thinking.
number
Top-K sampling parameter, only supported by some models.
boolean
default:"false"
Whether to enable streaming output, returns SSE format data chunks. Recommended to enable when using extended thinking.
array
List of stop sequences. Generation stops when the model produces these sequences.
array
Tool definitions list, supports function tools and web search tools.
object
Tool selection strategy, controls how the model uses tools.
object
Extended thinking configuration, enables Claudeโs deep reasoning capability.
The default for
| Sub-field | Type | Description |
|---|---|---|
type | enum | "adaptive": adaptive thinking โ the model decides when and how deeply to think; "disabled": turn thinking off. Claude 4.5 and earlier models use "enabled" together with budget_tokens |
display | enum | "summarized": return a summary of the thinking process; "omitted": do not return thinking content. Thinking still happens and costs the same โ omitted only hides it, and streaming reaches the reply text sooner. Cannot be combined with type: "disabled" |
budget_tokens | number | Only used with type: "enabled" (Claude 4.5 and earlier). Minimum 1024, and must be less than max_tokens; Claude 4.7 and newer models do not support this form |
{"type": "adaptive"} // adaptive thinking
{"type": "adaptive", "display": "summarized"} // adaptive thinking, return a thinking summary
{"type": "disabled"} // thinking off
display varies by model: Claude Fable 5, Opus 5, Sonnet 5, Opus 4.8 and Opus 4.7 default to "omitted"; Claude Opus 4.6, Sonnet 4.6 and earlier default to "summarized". To show the thinking process to users on the former, you must explicitly set "display": "summarized", otherwise the thinking content comes back empty.object
Output configuration, used to control the modelโs reasoning depth and token spend.
This parameter affects all tokens in the response (reply text, tool calls, and thinking), so it takes effect even without thinking enabled.Level availability varies by model:
| Sub-field | Type | Description |
|---|---|---|
effort | enum | Reasoning effort: "low" / "medium" / "high" / "xhigh" / "max", defaults to "high". Higher levels generally produce more accurate, more thorough answers but take longer and consume more tokens; try "xhigh" or "max" for coding and agentic work |
{"effort": "high"} // default level, identical to omitting the parameter
{"effort": "xhigh"} // coding / agentic long-horizon tasks
"xhigh" is only supported on Claude Fable 5, Opus 5, Opus 4.8, Opus 4.7 and Sonnet 5; Claude Sonnet 4.5 and earlier models do not support this parameter at all.On Claude Opus 5, thinking cannot be disabled at
"xhigh" or "max" effort โ combining those levels with "thinking": {"type": "disabled"} returns a 400 error. To disable thinking, set effort to "high" or lower.object
Request metadata for tracking and debugging.
array
MCP (Model Context Protocol) server configuration.
object
Context management configuration, controls how conversation context is handled.
object
Enables automatic caching. Placed at the top level of the request body, the system automatically applies the cache breakpoint to the last cacheable block and moves it forward as the conversation grows โ no markers to maintain. See Prompt Caching.
{"type": "ephemeral"} // 5-minute cache (default)
{"type": "ephemeral", "ttl": "1h"} // 1-hour cache
The legacy Amazon Bedrock integration (
InvokeModel / Converse, covering Opus 4.6 and earlier) does not support a top-level cache_control and returns 400. Use block-level explicit breakpoints for those models โ see Platform support.Prompt Caching
Prompt Caching allows you to cache frequently used context content, significantly reducing costs and improving response speed. There are two ways to enable it, usable separately or together:| Approach | How | When to use |
|---|---|---|
| Automatic caching | cache_control at the top level of the request body | Multi-turn conversations. The breakpoint lands on the last cacheable block and moves forward automatically โ nothing to maintain |
| Explicit breakpoints | cache_control marked on content blocks in system / messages | Precise control over the cache boundary โ e.g. caching only the system prompt or one long document |
Cache Control Parameters
Both approaches use the same field structure:| Field | Description |
|---|---|
type | Cache type, always "ephemeral" |
ttl | Cache lifetime, optional. Omit for a 5-minute cache (default, most cost-effective); set to "1h" for a 1-hour cache (suitable for long-term stable context, but writes cost more) |
{"type": "ephemeral"} // 5-minute cache (default)
{"type": "ephemeral", "ttl": "1h"} // 1-hour cache
Automatic caching (top-level cache_control)
Put cache_control at the root of the request body โ no markers on any content block:
{
"model": "claude-opus-5",
"max_tokens": 1024,
"cache_control": {"type": "ephemeral"},
"system": "You are a helpful assistant.",
"messages": [
{"role": "user", "content": "My name is Alex. I work on machine learning."},
{"role": "assistant", "content": "Nice to meet you, Alex!"},
{"role": "user", "content": "What did I say I work on?"}
]
}
| Request | Content (โ marks the breakpoint) | Cache behavior |
|---|---|---|
| 1 | System + User(1) + Asst(1) + User(2) โ | Everything written to cache |
| 2 | System + โฆ + User(2) + Asst(2) + User(3) โ | SystemโUser(2) read from cache; Asst(2) + User(3) written |
| 3 | System + โฆ + User(3) + Asst(3) + User(4) โ | SystemโUser(3) read from cache; Asst(3) + User(4) written |
Platform support
Automatic caching (top-levelcache_control) is available on every platform except the legacy Amazon Bedrock integration:
| Platform | Top-level cache_control |
|---|---|
| Anthropic API (first-party) | โ |
| Claude Platform on AWS (Anthropic-operated, AWS Marketplace billing) | โ |
| Claude in Amazon Bedrock (Messages API endpoint, Opus 4.7 and later) | โ |
Legacy Claude on Amazon Bedrock (InvokeModel / Converse, Opus 4.6 and earlier) | โ returns 400 |
| Google Vertex AI | โ |
| Microsoft Foundry | โ |
| Model | Top-level cache_control | Notes |
|---|---|---|
| Fable 5, Opus 5, Opus 4.8, Opus 4.7, Sonnet 5 | โ | Served by the Messages API endpoint; model IDs look like anthropic.claude-opus-5 (no ARN version) |
| Opus 4.6, Sonnet 4.6, Opus 4.5, Sonnet 4.5, Sonnet 4 | โ | Served by the legacy InvokeModel / Converse APIs with ARN-versioned model IDs โ use explicit breakpoints |
If youโre unsure which path a model actually takes, send the same prefix twice and check whether
usage.cache_read_input_tokens is greater than 0 on the second response.Explicit breakpoints (block-level cache_control)
Mark the field inside system array elements or content array elements in messages:
{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": "Long, stable context...",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Long document to cache...",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}
]
}
]
}
Combining both approaches
Automatic caching and explicit breakpoints work together. The typical pattern is an explicit breakpoint pinning the system prompt while automatic caching handles the growing conversation:{
"model": "claude-opus-5",
"max_tokens": 1024,
"cache_control": {"type": "ephemeral"},
"system": [
{
"type": "text",
"text": "Long, stable system prompt...",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [
{"role": "user", "content": "What are the key terms?"}
]
}
- Automatic caching uses one of the 4 breakpoint slots
- Sending a top-level
cache_controlwhen 4 explicit breakpoints already exist returns 400 (no slots left) - If the last block already has an explicit
cache_controlwith the samettl, automatic caching is a no-op and consumes no extra slot - If the last block has an explicit
cache_controlwith a differentttl, the API returns 400 - If the last block is not eligible as a breakpoint target, the system walks backward to the nearest eligible block; if none is found, caching is skipped (no error)
Caching Mechanism
- Cache Breakpoints: Up to 4 content blocks can be marked per request. Each breakpoint writes its own cache entry covering the entire prefix from the beginning up to and including that block
- Cache Hits: The system compares the prefix at your breakpoint; if there is no match it walks backward one block at a time, with a lookback window of up to 20 content blocks. Cache entries outside that window will not be hit โ add an earlier breakpoint in that case
- Cache Threshold: Content shorter than the modelโs minimum cacheable length is not cached (no error is returned; it is simply processed as regular input). See the per-model table below
- Cache Duration: 5 minutes (default) or 1 hour
- Cost: Cache reads are 10% of the regular input price (90% cheaper); cache writes carry a premium โ 1.25x for the 5-minute cache and 2x for the 1-hour cache
Minimum Cacheable Length by Model
| Model | Minimum Cacheable Length |
|---|---|
| Claude Fable 5, Claude Opus 5 | 512 tokens |
| Claude Opus 4.8, Claude Sonnet 5, Claude Sonnet 4.6, Claude Sonnet 4.5 | 1,024 tokens |
| Claude Opus 4.7 | 2,048 tokens |
| Claude Opus 4.6, Claude Opus 4.5, Claude Haiku 4.5 | 4,096 tokens |
Use Cases
- Long Document Analysis: Cache large documents in
system, ask multiple questions - Codebase Understanding: Cache code context for multi-turn code analysis
- Knowledge Base Q&A: Cache knowledge base content for fast queries
- Multi-turn Conversations: Cache conversation history to maintain context coherence
Basic Examples
- Non-streaming Request
- Streaming Request (SSE)
- Python Example (Anthropic SDK)
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "Please briefly introduce artificial intelligence"}
]
}'
curl -N -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"stream": true,
"messages": [
{"role": "user", "content": "Please briefly introduce artificial intelligence"}
]
}'
from anthropic import Anthropic
client = Anthropic(
api_key="sk-xxxxxxxxxx",
base_url="https://api.gravitex.ai"
)
# Non-streaming
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
messages=[
{"role": "user", "content": "Please briefly introduce artificial intelligence"}
]
)
print(message.content[0].text)
# Streaming
with client.messages.stream(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
messages=[
{"role": "user", "content": "Please briefly introduce artificial intelligence"}
]
) as stream:
for text_block in stream.text_stream:
print(text_block, end="")
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Artificial intelligence is a branch of computer science that focuses on creating intelligent machines capable of performing tasks that typically require human intelligence..."
}
],
"model": "claude-sonnet-4-5-20250929",
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 25,
"output_tokens": 100
}
}
Advanced Features
System Prompt
System prompts can be set as a string or an array of media content:- String Format
- Array Format
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"system": "You are a helpful assistant that excels at answering questions.",
"messages": [
{"role": "user", "content": "What is machine learning?"}
]
}'
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"system": [
{"type": "text", "text": "You are a helpful assistant that excels at answering questions."}
],
"messages": [
{"role": "user", "content": "What is machine learning?"}
]
}'
Extended Thinking
Claude supports extended thinking, allowing the model to perform deep reasoning. When enabled, the model will think internally before generating the final answer.- Basic Usage
- Python Example
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 4096,
"temperature": 1.0,
"top_p": 0,
"stream": true,
"messages": [
{"role": "user", "content": "Give a medium difficulty geometry problem and solve it step by step"}
]
}'
from anthropic import Anthropic
client = Anthropic(
api_key="sk-xxxxxxxxxx",
base_url="https://api.gravitex.ai"
)
with client.messages.stream(
model="claude-sonnet-4-5-20250929",
max_tokens=4096,
thinking={
"type": "enabled",
"budget_tokens": 4096
},
temperature=1.0,
top_p=0,
messages=[
{"role": "user", "content": "Give a medium difficulty geometry problem and solve it step by step"}
]
) as stream:
for event in stream:
if event.type == "content_block_delta":
if hasattr(event.delta, "thinking"):
# Thinking process
print(f"[Thinking] {event.delta.thinking}", end="")
elif hasattr(event.delta, "text"):
# Final answer
print(event.delta.text, end="")
budget_tokensmust be greater than 1024- When using extended thinking, itโs recommended to set
temperature: 1.0andtop_p: 0 - Streaming output (
stream: true) must be enabled to see the thinking process
Tool Calling
Supports function tools and web search tools:- Function Tools
- Claude Official Web Search Tool
- Complete Tool Calling Flow
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "Get weather information for a city",
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name"
}
},
"required": ["city"]
}
}
],
"tool_choice": {
"type": "auto"
},
"messages": [
{"role": "user", "content": "What is the weather in Shanghai?"}
]
}'
Claude supports the official web search tool Basic Usage:With Search Limit:With Location Information (Improves Search Accuracy):Python Example:
web_search_20250305, which can search the web in real-time and include citation sources in responses.Note: AWS Bedrock does not support this search tool
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"tools": [
{
"type": "web_search_20250305",
"name": "web_search"
}
],
"messages": [
{"role": "user", "content": "What are the latest news about artificial intelligence?"}
]
}'
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"tools": [
{
"type": "web_search_20250305",
"name": "web_search",
"max_uses": 5
}
],
"messages": [
{"role": "user", "content": "Search for today'\''s weather in Beijing"}
]
}'
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"tools": [
{
"type": "web_search_20250305",
"name": "web_search",
"max_uses": 5,
"user_location": {
"type": "approximate",
"timezone": "Asia/Shanghai",
"country": "CN",
"region": "Beijing",
"city": "Beijing"
}
}
],
"messages": [
{"role": "user", "content": "What'\''s the weather in Shanghai today?"}
]
}'
from anthropic import Anthropic
client = Anthropic(
api_key="sk-xxxxxxxxxx",
base_url="https://api.gravitex.ai"
)
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
tools=[
{
"type": "web_search_20250305",
"name": "web_search",
"max_uses": 5
}
],
messages=[
{"role": "user", "content": "What are the latest news about artificial intelligence?"}
]
)
print(message.content[0].text)
typemust be"web_search_20250305"namemust be"web_search"max_uses(optional): Maximum number of search uses in a single conversation, recommended value: 2-10user_location(optional): User location information to improve localization accuracy of search results- Search results will automatically include citation sources in the response
- Supported models include Claude Sonnet 4.5, Claude Opus 4.5, Claude Haiku 4.5, etc.
Phase 1: Model returns tool call requestPhase 2: Return tool execution result
{
"id": "msg_xxx",
"content": [
{
"type": "tool_use",
"id": "toolu_xxx",
"name": "get_weather",
"input": {"city": "Shanghai"}
}
],
"stop_reason": "tool_use"
}
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"tools": [...],
"messages": [
{"role": "user", "content": "What is the weather in Shanghai?"},
{
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": "toolu_xxx",
"name": "get_weather",
"input": {"city": "Shanghai"}
}
]
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_xxx",
"content": "{\"temp\":\"22ยฐC\",\"condition\":\"Cloudy\",\"aqi\":53}"
}
]
}
]
}'
tool_choice Parameter Details
tool_choice controls how the model uses tools:
| Value | Description |
|---|---|
{"type": "auto"} | Automatically decide whether to use tools (default) |
{"type": "any"} | Must use at least one tool |
{"type": "none"} | Donโt use any tools |
{"type": "tool", "name": "tool_name"} | Must use the specified tool |
{
"tool_choice": {
"type": "auto",
"disable_parallel_tool_use": false
}
}
Multimodal Input (Images)
Supports including images in messages:curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
}
},
{
"type": "text",
"text": "What is in this image?"
}
]
}
]
}'
Prompt Caching
Caching frequently used context content can significantly reduce costs and improve response speed.- System Cache (5 minutes)
- Messages Cache (1 hour)
- Python SDK Example
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": "You are a professional technical documentation analyst. Here is the complete AWS Lambda technical documentation:\n\nAWS Lambda is a serverless computing service...[large documentation content, at least 1024 tokens]",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [
{"role": "user", "content": "What is Lambda's pricing model?"}
]
}'
{
"usage": {
"input_tokens": 50,
"cache_creation_input_tokens": 1200,
"cache_read_input_tokens": 0,
"output_tokens": 150
}
}
{
"usage": {
"input_tokens": 45,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 1200,
"output_tokens": 100
}
}
curl -X POST "https://api.gravitex.ai/v1/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"max_tokens": 1024,
"system": "You are a Python programming assistant",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Analyze this code:\n```python\n[large code snippet, at least 1024 tokens]\n```",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}
]
},
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "The main functionality of this code is...[detailed analysis]",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}
]
},
{
"role": "user",
"content": "How can I optimize the performance of this code?"
}
]
}'
ttl: "1h"):- 1-hour cache duration, suitable for long sessions
- Ideal for code reviews, document analysis, etc.
- Faster subsequent requests after cache hit
from anthropic import Anthropic
client = Anthropic(
api_key="sk-xxxxxxxxxx",
base_url="https://api.gravitex.ai"
)
# First request: Create cache
message1 = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
system=[
{
"type": "text",
"text": "You are a professional document analyst...[long text content]",
"cache_control": {"type": "ephemeral"}
}
],
messages=[
{"role": "user", "content": "First question"}
]
)
print(f"Cache created: {message1.usage.cache_creation_input_tokens} tokens")
print(f"Cache read: {message1.usage.cache_read_input_tokens} tokens")
# Second request within 5 minutes: Use cache
message2 = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=1024,
system=[
{
"type": "text",
"text": "You are a professional document analyst...[same long text]",
"cache_control": {"type": "ephemeral"}
}
],
messages=[
{"role": "user", "content": "Second question"}
]
)
print(f"Cache created: {message2.usage.cache_creation_input_tokens} tokens")
print(f"Cache read: {message2.usage.cache_read_input_tokens} tokens")
Cache Key Points:
- Content must meet the modelโs minimum cacheable length to trigger caching (512โ4,096 tokens depending on the model โ see the table above)
- Without
ttl, the cache is valid for 5 minutes - With
ttl: "1h", the cache is valid for 1 hour - Cache reads cost 90% less than regular inputs; cache writes carry a premium (1.25x for 5 minutes, 2x for 1 hour)
- Up to 4 blocks can be marked per request, and each breakpoint writes its own cache entry
- Cache is based on exact content match; any changes invalidate the cache
Best Practices:
- Place unchanging long context (documents, codebases, etc.) in
systemwith caching enabled - Use the 1-hour cache (
ttl: "1h") for long-term stable content - Use the default 5-minute cache (omit
ttl) for frequently changing content - Cache conversation history in multi-turn dialogues
- Monitor
cache_creation_input_tokensandcache_read_input_tokensto optimize costs
Response Format
- Non-streaming Response
- Streaming Response
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Response content..."
}
],
"model": "claude-sonnet-4-5-20250929",
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 25,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0,
"output_tokens": 100
}
}
input_tokens: Non-cached input tokens for the current requestcache_creation_input_tokens: Tokens cached for the first time (only present in first request)cache_read_input_tokens: Tokens read from cache (present when cache hits)output_tokens: Generated output tokens
Streaming responses are returned in SSE (Server-Sent Events) format, containing the following event types:When using extended thinking,
message_start: Message startcontent_block_start: Content block startcontent_block_delta: Content delta (containstextorthinking)content_block_stop: Content block endmessage_delta: Message delta (contains usage info)message_stop: Message end
event: message_start
data: {"type":"message_start","message":{"id":"msg_xxx","type":"message","role":"assistant","content":[],"model":"claude-sonnet-4-5-20250929","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":25,"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":"Response"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" content"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":100}}
event: message_stop
data: {"type":"message_stop"}
content_block_delta may contain a thinking field:event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"Let me think about this problem..."}}
Error Handling
The system processes upstream Claude API errors and returns standardized error response formats.| Error Type | HTTP Status Code | Description |
|---|---|---|
invalid_request | 400 | Request parameter error (e.g., missing required fields) |
authentication_error | 401 | Invalid or unauthorized API key |
rate_limit_error | 429 | Request rate limit exceeded |
upstream_error | 500 | Upstream service error |
gravitex_api_error | 500 | System internal error |
{
"error": {
"type": "invalid_request",
"message": "field messages is required"
}
}
Comparison with /v1/chat/completions
| Feature | /v1/messages | /v1/chat/completions |
|---|---|---|
| Authentication | Authorization: Bearer | Authorization: Bearer |
| Response Format | Anthropic native format | OpenAI compatible format |
| Extended Thinking | Native thinking parameter | Via reasoning_effort or reasoning parameter |
| Tool Calling | Native tools and tool_choice | OpenAI compatible format |
| Suitable Clients | Anthropic SDK, Claude Code | OpenAI SDK, compatible clients |
- If youโre using Claude Code or other Anthropic native clients, we recommend using the
/v1/messagesendpoint - If youโre using OpenAI SDK or need OpenAI format compatibility, we recommend using the
/v1/chat/completionsendpoint - Both endpoints have essentially the same functionality, the main difference is in request/response format
Notes
max_tokensis a required parameter and must be greater than 0messagesarray cannot be empty- When using extended thinking,
budget_tokensmust be greater than 1024 - Extended thinking requires streaming output to see the thinking process
- Tool calling requires multiple rounds of interaction: first round returns tool call request, second round returns tool execution result
- Image input requires base64 encoding
- Using streaming output can improve first token response time and interaction experience
- Tool calling should have proper timeout and retry mechanisms to avoid blocking model responses
- Extended thinking can significantly improve reasoning quality for complex problems
Related Resources
Chat Completions (OpenAI Compatible)
View OpenAI compatible chat endpoint documentation
Model List
View all supported model information
