# Claude API — cURL / Raw HTTP Use these examples when the user needs raw HTTP requests or is working in a language without an official SDK. ## Setup ```bash export ANTHROPIC_API_KEY="your-api-key" ``` --- ## Basic Message Request ```bash curl https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "{{OPUS_ID}}", "max_tokens": 16000, "messages": [ {"role": "user", "content": "What is the capital of France?"} ] }' ``` ### Parsing the response Use `jq` to extract fields from the JSON response. Do not use `grep`/`sed` — JSON strings can contain any character and regex parsing will break on quotes, escapes, or multi-line content. ```bash # Capture the response, then extract fields response=$(curl -s https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d '{"model":"{{OPUS_ID}}","max_tokens":16000,"messages":[{"role":"user","content":"Hello"}]}') # Print the first text block (-r strips the JSON quotes) echo "$response" | jq -r '.content[0].text' # Read usage fields input_tokens=$(echo "$response" | jq -r '.usage.input_tokens') output_tokens=$(echo "$response" | jq -r '.usage.output_tokens') # Read stop reason (for tool-use loops) stop_reason=$(echo "$response" | jq -r '.stop_reason') # Extract all text blocks (content is an array; filter to type=="text") echo "$response" | jq -r '.content[] | select(.type == "text") | .text' ``` --- ## Streaming (SSE) ```bash curl https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "{{OPUS_ID}}", "max_tokens": 64000, "stream": true, "messages": [{"role": "user", "content": "Write a haiku"}] }' ``` The response is a stream of Server-Sent Events: ``` event: message_start data: {"type":"message_start","message":{"id":"msg_...","type":"message",...}} 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":"Hello"}} event: content_block_stop data: {"type":"content_block_stop","index":0} event: message_delta data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":12}} event: message_stop data: {"type":"message_stop"} ``` --- ## Tool Use ```bash curl https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "{{OPUS_ID}}", "max_tokens": 16000, "tools": [{ "name": "get_weather", "description": "Get current weather for a location", "input_schema": { "type": "object", "properties": { "location": {"type": "string", "description": "City name"} }, "required": ["location"] } }], "messages": [{"role": "user", "content": "What is the weather in Paris?"}] }' ``` When Claude responds with a `tool_use` block, send the result back: ```bash curl https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "{{OPUS_ID}}", "max_tokens": 16000, "tools": [{ "name": "get_weather", "description": "Get current weather for a location", "input_schema": { "type": "object", "properties": { "location": {"type": "string", "description": "City name"} }, "required": ["location"] } }], "messages": [ {"role": "user", "content": "What is the weather in Paris?"}, {"role": "assistant", "content": [ {"type": "text", "text": "Let me check the weather."}, {"type": "tool_use", "id": "toolu_abc123", "name": "get_weather", "input": {"location": "Paris"}} ]}, {"role": "user", "content": [ {"type": "tool_result", "tool_use_id": "toolu_abc123", "content": "72°F and sunny"} ]} ] }' ``` --- ## Prompt Caching Put `cache_control` on the last block of the stable prefix. See `shared/prompt-caching.md` for placement patterns and the silent-invalidator audit checklist. ```bash curl https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "{{OPUS_ID}}", "max_tokens": 16000, "system": [ {"type": "text", "text": "", "cache_control": {"type": "ephemeral"}} ], "messages": [{"role": "user", "content": "Summarize the key points"}] }' ``` For 1-hour TTL: `"cache_control": {"type": "ephemeral", "ttl": "1h"}`. Top-level `"cache_control"` on the request body auto-places on the last cacheable block. Verify hits via the response `usage.cache_creation_input_tokens` / `usage.cache_read_input_tokens` fields. --- ## Extended Thinking > **Fable 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6:** Use adaptive thinking. `budget_tokens` is removed on Fable 5, Opus 4.8, and 4.7 (400 if sent); deprecated on Opus 4.6 and Sonnet 4.6. > **Older models:** Use `"type": "enabled"` with `"budget_tokens": N` (must be < `max_tokens`, min 1024). ```bash # Fable 5 / Opus 4.8 / 4.7 / 4.6: adaptive thinking (recommended) curl https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "{{OPUS_ID}}", "max_tokens": 16000, "thinking": { "type": "adaptive", "display": "summarized" }, "output_config": { "effort": "high" }, "messages": [{"role": "user", "content": "Solve this step by step..."}] }' ``` --- ## Refusal Fallbacks ({{FABLE_NAME}}) — opt in by default On `{{FABLE_ID}}`, safety classifiers may decline a request (HTTP 200 with `stop_reason: "refusal"`). Fallbacks are **opt-in**: without them the request simply stops. Include the `fallbacks` parameter and its beta header by default — on a policy decline the API re-runs the same request on the fallback model inside the same call. A decline before any output isn't billed (a mid-stream decline bills the streamed partial); the rescue bills at the fallback model's own rates. ```bash response=$(curl -s https://api.anthropic.com/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "anthropic-beta: server-side-fallback-2026-06-01" \ -d '{ "model": "{{FABLE_ID}}", "max_tokens": 16000, "fallbacks": [{"model": "{{OPUS_ID}}"}], "messages": [{"role": "user", "content": "Hello"}] }') # Which model produced the message echo "$response" | jq -r '.model' # Refusal on the final response means the whole chain refused echo "$response" | jq -r '.stop_reason' # Switch points: one fallback block per model that ran and declined this turn echo "$response" | jq -r '.content[] | select(.type == "fallback") | "\(.from.model) declined; \(.to.model) continued"' # Served-by signal — covers sticky turns, which carry no fallback block. # Pair with stop_reason: the fallback model can itself refuse. if [ "$(echo "$response" | jq -r '.stop_reason')" != "refusal" ] && \ echo "$response" | jq -e '[.usage.iterations[]? | select(.type == "fallback_message")] | length > 0' > /dev/null; then echo "fallback model served this turn" fi ``` The header must be exactly `server-side-fallback-2026-06-01`. The parameter is rejected on the Batches API and unavailable on Amazon Bedrock, Vertex AI, and Microsoft Foundry. Full semantics (sticky routing, billing, streaming, echoing fallback turns back): `shared/model-migration.md` → Migrating to {{FABLE_NAME}} → `refusal` stop reason. --- ## Required Headers | Header | Value | Description | | ------------------- | ------------------ | -------------------------- | | `Content-Type` | `application/json` | Required | | `x-api-key` | Your API key | Authentication | | `anthropic-version` | `2023-06-01` | API version | | `anthropic-beta` | Beta feature IDs | Required for beta features |