Get API Key Get API
Docs

Claude Context Caching Guide

Cache reusable prompt prefixes through the Claude Messages API or the OpenAI-compatible Chat Completions API to reduce token costs from repeatedly processing long content.

Claude context caching (Context Cache) is designed for reusing long prefixes such as system prompts, documents, codebases, or conversation history. Add cache_control to a stable prefix so that the first request creates a cache and subsequent requests can read the unexpired cache.

Before you begin, set your API key:

export API_KEY="YOUR_API_KEY"
Note

The examples in this guide use claude-sonnet-5. Refer to the platform's model documentation to confirm whether other models support context caching.

Use cases

When multiple requests repeatedly include the same large body of content, you can cache a stable prefix, such as:

  • A long system prompt
  • A fixed knowledge base or product documentation
  • Conversation history that remains unchanged across a multi-turn conversation
  • Reused codebases, tool definitions, and instructions

Context caching is ideal for requests where the content at the beginning remains unchanged while the final question keeps changing.

Claude Messages API

5-minute cache

Add cache_control to the content block you want to cache:

curl "https://api.openveer.com/v1/messages" \
  -H "x-api-key: $API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 1024,
    "system": [
      {
        "type": "text",
        "text": "Place the long prefix you want to reuse here...",
        "cache_control": {
          "type": "ephemeral"
        }
      }
    ],
    "messages": [
      {
        "role": "user",
        "content": "Answer the question based on the content above."
      }
    ]
  }'
Warning

system must be an array of content blocks. A string-form system cannot include cache_control.

If ttl is omitted, the cache lifetime defaults to 5 minutes.

1-hour cache

To use a 1-hour cache, add the anthropic-beta request header and set ttl to 1h:

curl "https://api.openveer.com/v1/messages" \
  -H "x-api-key: $API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: extended-cache-ttl-2025-04-11" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 1024,
    "system": [
      {
        "type": "text",
        "text": "Place the long prefix you want to reuse here...",
        "cache_control": {
          "type": "ephemeral",
          "ttl": "1h"
        }
      }
    ],
    "messages": [
      {
        "role": "user",
        "content": "Answer the question based on the content above."
      }
    ]
  }'

Supported TTL values:

TTL Meaning
5m Cache for 5 minutes; this value is used when ttl is omitted
1h Cache for 1 hour; the corresponding anthropic-beta request header is also required

Response usage fields

The Claude Messages API reports regular input, cache-write, and cache-read tokens separately in usage:

{
  "usage": {
    "input_tokens": 23,
    "cache_creation_input_tokens": 2619,
    "cache_read_input_tokens": 0,
    "cache_creation": {
      "ephemeral_5m_input_tokens": 2619,
      "ephemeral_1h_input_tokens": 0
    },
    "output_tokens": 24
  }
}

Calculate total input tokens as follows:

input_tokens
+ cache_creation_input_tokens
+ cache_read_input_tokens

These three values do not overlap. The first request usually has cache_creation_input_tokens > 0. When you send the same stable prefix again, you should see cache_read_input_tokens > 0.

OpenAI-compatible API

Request example

When using caching through /v1/chat/completions, the cache_control structure is similar to the Claude Messages API:

curl "https://api.openveer.com/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "system",
        "content": [
          {
            "type": "text",
            "text": "Place the long prefix you want to reuse here...",
            "cache_control": {
              "type": "ephemeral"
            }
          }
        ]
      },
      {
        "role": "user",
        "content": "Answer the question based on the content above."
      }
    ]
  }'

1-hour cache

The OpenAI-compatible format also supports 1-hour caching. Add the anthropic-beta request header and set ttl: "1h" in cache_control:

-H "anthropic-beta: extended-cache-ttl-2025-04-11"
"cache_control": {
  "type": "ephemeral",
  "ttl": "1h"
}

content must be an array

In the OpenAI-compatible format, cache_control must be placed in a specific content block. It cannot be attached to a string-form message.

{
  "role": "system",
  "content": "Place the long prefix here...",
  "cache_control": {
    "type": "ephemeral"
  }
}

The structure above does not enable caching, and the request does not return an error. Use the following structure instead:

{
  "role": "system",
  "content": [
    {
      "type": "text",
      "text": "Place the long prefix here...",
      "cache_control": {
        "type": "ephemeral"
      }
    }
  ]
}
Warning

If content is a string, the cache marker is ignored and the input is processed as regular input. Check the cache usage fields in the response to confirm whether the cache was hit.

Cache user or assistant content blocks

You can also add cache_control to a content block in a user or assistant message to cache a long document or a multi-turn conversation prefix:

{
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": "Place the long document you want to reuse here...",
      "cache_control": {
        "type": "ephemeral"
      }
    },
    {
      "type": "text",
      "text": "Summarize the three main points in the document above."
    }
  ]
}

Split the stable content and the current question into separate content blocks, and add cache_control only to the stable content block.

Response usage fields

The OpenAI-compatible format uses different fields to report cache usage:

{
  "usage": {
    "prompt_tokens": 1942,
    "completion_tokens": 22,
    "prompt_tokens_details": {
      "cached_tokens": 1921,
      "cache_write_tokens": 0
    },
    "claude_cache_creation_5_m_tokens": 0,
    "claude_cache_creation_1_h_tokens": 0
  }
}

Field mapping:

Meaning Claude Messages API OpenAI-compatible API
Total input Sum of the three input fields prompt_tokens
Cache read cache_read_input_tokens prompt_tokens_details.cached_tokens
General cache-write field cache_creation_input_tokens prompt_tokens_details.cache_write_tokens (only populated when no TTL breakdown is available)
5-minute cache write cache_creation.ephemeral_5m_input_tokens claude_cache_creation_5_m_tokens
1-hour cache write cache_creation.ephemeral_1h_input_tokens claude_cache_creation_1_h_tokens
Output output_tokens completion_tokens
Note

If prompt_tokens_details.cache_write_tokens is 0, also check claude_cache_creation_5_m_tokens and claude_cache_creation_1_h_tokens. When TTL-specific fields are available, the cache-write amount is returned in the corresponding field.

Note

The numbers and units in claude_cache_creation_5_m_tokens and claude_cache_creation_1_h_tokens are separated by underscores. Use the field names exactly as returned in the response.

Warning

The OpenAI-compatible endpoint may return an SSE streaming response even when you do not explicitly pass stream: true. Clients should support parsing chat.completion.chunk; usage is included in the final data chunk that contains usage.

Conditions for a cache hit

The prefix meets the minimum length

For the model used in these examples, the cache prefix usually needs to be at least approximately 1024 tokens. If the prefix is too short, the cache marker may be ignored without an error.

The prefix remains byte-identical

The text, spaces, line breaks, and content-block order in the cache prefix must remain identical. Do not add timestamps, random IDs, request counters, or other dynamic content to the stable prefix.

The request does not trigger a model refusal

If the request triggers a model refusal, the response may still report cache-creation tokens, but that cache is not read on the next request. When troubleshooting a cache miss, also check whether stop_reason is refusal.

The cache is still valid

The cache lifetime is 5 minutes or 1 hour and is calculated from the most recent access. A cache hit refreshes the lifetime.

Billing usage

Cache-related usage falls into three categories:

Usage When it occurs
Cache write When the cache is first created
Cache read When a subsequent request hits the cache
Regular input Input outside the cached prefix

The three categories do not overlap. Cache writes usually cost more than regular input, while cache reads usually cost less. Context caching is therefore best suited to stable prefixes that will be reused within the TTL.

Minimal reproducible example

The script below generates a sufficiently long stable prefix and sends the same request twice in succession. The second response should have cache_read_input_tokens > 0.

python3 - <<'PY' > /tmp/claude-cache-request.json
import json

paragraph = (
    "Prompt caching stores a prefix of the request so that later requests "
    "can reuse the same byte-identical prefix without processing it again. "
)

system_text = (
    "You are a documentation assistant. Reference material follows.\n\n"
    + paragraph * 40
)

print(json.dumps({
    "model": "claude-sonnet-5",
    "max_tokens": 32,
    "system": [{
        "type": "text",
        "text": system_text,
        "cache_control": {"type": "ephemeral"}
    }],
    "messages": [{
        "role": "user",
        "content": "In one sentence, what must remain unchanged?"
    }]
}))
PY

for request_number in 1 2; do
  echo "Request ${request_number}"
  curl -s "https://api.openveer.com/v1/messages" \
    -H "x-api-key: $API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "Content-Type: application/json" \
    --data @/tmp/claude-cache-request.json \
  | python3 -c "import json, sys; print(json.load(sys.stdin)['usage'])"
done

Expected result:

Request 1: cache_creation_input_tokens > 0, cache_read_input_tokens = 0
Request 2: cache_creation_input_tokens = 0, cache_read_input_tokens > 0

Troubleshooting checklist

If the cache is not hit, check the following in order:

  • Whether stop_reason is refusal
  • Whether the cache prefix meets the model's minimum token requirement
  • Whether the stable prefix is byte-identical across both requests
  • Whether content is an array in the OpenAI-compatible format
  • Whether cache_control is placed in a specific content block
  • Whether a 1-hour cache includes both ttl: "1h" and the corresponding anthropic-beta request header
  • Whether the cache has exceeded its TTL
  • Whether you are reading the cache usage fields for the endpoint you are using

This documentation is built and hosted on Mintlify, a developer documentation platform.