← Blog

Claude API Response Caching to Reduce Cost

2026-10-21 · 5 min read · SubToAPI Team

If you're spending more on Claude API calls than expected, caching is the single most effective lever you have. There are two distinct caching strategies you should be using together: prompt caching (a native Claude feature that discounts repeated input tokens) and application-level response caching (storing full responses so you skip the API call entirely for repeated requests). Most teams only use one, and leave significant savings on the table.

This article covers both, shows you how to implement them, and explains when each one actually helps versus when it's wasted effort.

The two layers of caching you need

Prompt caching happens on Anthropic's side. You mark part of your prompt (a system prompt, a long document, a set of tool definitions) as cacheable, and subsequent requests that reuse that exact prefix get charged a fraction of the normal input token price for the cached portion. This is ideal when you send the same large context repeatedly — a RAG document, a codebase excerpt, a set of few-shot examples — with only the user's question changing.

Application-level response caching happens in your own infrastructure, before the request ever reaches Claude. If a user asks the exact same question twice, or if ten users trigger the same classification prompt on the same input, you don't need to call the model at all — you serve the cached response. This saves 100% of the cost for that call, not just a discount on input tokens.

Used together, you can cut a meaningful chunk of your Claude spend without changing your prompts or your product behavior.

Using native prompt caching

Anthropic's prompt caching works by marking a block in your request with cache_control. The first call writes the cache; subsequent calls within the cache lifetime (currently a few minutes, refreshed on each hit) read from it at a steep discount.

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-4-20250514",
    "max_tokens": 1024,
    "system": [
      {
        "type": "text",
        "text": "<your long system prompt or document here>",
        "cache_control": {"type": "ephemeral"}
      }
    ],
    "messages": [
      {"role": "user", "content": "Summarize section 3."}
    ]
  }'

Good candidates for prompt caching:

Prompt caching does not help if every request has unique content throughout — there's nothing stable to cache. It also doesn't eliminate the API call itself; you still pay for output tokens and get a new generation each time.

Application-level response caching

This is where you skip the call entirely. The pattern is simple: hash the inputs that determine the output, check your cache, and only call Claude on a miss.

import crypto from "crypto";

const cache = new Map(); // swap for Redis in production
const TTL_MS = 10 * 60 * 1000;

function cacheKey(systemPrompt, userMessage, model) {
  return crypto
    .createHash("sha256")
    .update(systemPrompt + "::" + userMessage + "::" + model)
    .digest("hex");
}

async function askClaude(systemPrompt, userMessage, model) {
  const key = cacheKey(systemPrompt, userMessage, model);
  const hit = cache.get(key);

  if (hit && Date.now() - hit.timestamp < TTL_MS) {
    return hit.response;
  }

  const res = await fetch("https://api.subtoapi.app/v1/messages", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SUBTOAPI_KEY}`,
      "content-type": "application/json",
    },
    body: JSON.stringify({
      model,
      max_tokens: 1024,
      system: systemPrompt,
      messages: [{ role: "user", content: userMessage }],
    }),
  });

  const data = await res.json();
  cache.set(key, { response: data, timestamp: Date.now() });
  return data;
}

This pattern pays off most for:

It pays off least for anything conversational or personalized, where the input is unique per request by design. Don't cache responses that depend on real-time data (stock prices, current date, live search results) unless your TTL is short enough to stay accurate.

Cache invalidation: the part people skip

A cache with no invalidation strategy is a bug generator. Set a TTL that matches how often the underlying "truth" changes — minutes for anything time-sensitive, hours or days for static reference content. If your system prompt or document changes, make sure your cache key includes a version identifier for it, otherwise you'll serve stale answers against an updated prompt.

For semantically similar-but-not-identical queries ("what's your refund policy" vs "how do refunds work"), exact-match hashing won't catch the overlap. That requires embedding-based similarity caching, which is a heavier lift and only worth it at high query volume with a narrow domain.

Combining both for maximum savings

A well-tuned pipeline looks like this: check your application cache first (zero cost on a hit), and if it's a miss, send the request with prompt caching enabled on the stable parts of your context (reduced cost on a hit, full cost only on a true first-time call). This stacks the savings — most requests cost nothing, and the ones that do reach Claude are cheaper than they'd otherwise be.

If you're running this through SubToAPI, the dashboard's usage metadata shows token counts per request, so you can measure how much your caching layer is actually saving before and after you ship it — see /docs/messages for the response fields and /docs/streaming if you're caching around streamed responses. You can test the setup free at /signup; plans start at €9/month on the Solo tier, see /pricing for details.

questions

Does prompt caching change the model's output? No. It only affects billing and latency for the cached portion of the input. The model still generates a fresh response to your actual message every time.

How long does Claude's prompt cache last? The cache lifetime is short — typically a few minutes — and refreshes on each cache hit. It's designed for bursts of related requests, not long-term storage, which is why application-level caching is still necessary for less frequent repeats.

Is application-level caching safe for all Claude use cases? It's safe for deterministic or near-deterministic tasks like classification, extraction, and FAQ-style answers. Avoid it for conversational, personalized, or time-sensitive queries where a stale cached response would be misleading or wrong.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →