The gateway cache is on by default and needs no code changes. Provider prompt caching is opt-in per request via
cache_control markers.
Gateway response cache
When a request is byte-for-byte equivalent to one served recently, MeshAPI returns the stored response and never calls the provider. The result is a response in single-digit milliseconds at no token cost. The response cache coversPOST /v1/chat/completions and POST /v1/messages. It also covers POST /v1/responses in two cases:
- the request sets
store: false; - the model has no native Responses API, so MeshAPI translates the request.
store: true is the default. A Responses request is matched on its whole body, apart from stream, user and service_tier, rather than on the fields below. A hit replays the answer in the Responses format.
What counts as “identical”
The cache key is a SHA-256 hash over exactly these fields:model- the resolved upstream
provider messagesmax_tokensstopresponse_formatservice_tier, when the request selected one — see Service Tiers- each of
temperature,seed,top_p,frequency_penalty,presence_penalty,reasoning_effortandreasoning, when the request sets it (unset is its own value, not0) - the parameters the serving model could not accept and Mesh withheld, if any
streamis not part of the key. A streaming request can be served from a response originally stored by a non-streaming one; MeshAPI replays it as normal SSE chunks. Your streaming client sees no difference.useris not part of the key. Passing a differentuservalue does not give you a different cache entry.
When caching applies
A request is eligible only if all of these hold:Detecting a cache hit
A response served from the cache carries:There is no
X-Cache: MISS header. The header is present only on a hit — treat its absence as a miss rather than checking for a MISS value.X-Cache: HIT responses to measure your hit rate. The per-request Usage API events don’t carry the hit marker, so you can’t filter on it there.
Turning it off
Caching is enabled by default. You can opt out per request in two ways:- Request header
- Request body
Cache isolation
By default each account gets its own cache namespace: your responses are never served to another tenant, even for an identical prompt. Accounts may opt into a shared namespace, where entries are keyed by content hash alone and hit rates are higher because the cache is warmed by all participants. Shared caching is off unless you ask for it.Freshness
Entries live for 24 hours. There is no explicit invalidation API — if you need a guaranteed-fresh answer, sendX-Mesh-Cache: no-store.
Provider prompt caching
Provider prompt caching is a different mechanism: instead of reusing a whole response, the provider stores the processed prefix of your prompt and charges less for it on subsequent requests. It pays off when you send a large, stable block — a long system prompt, a document, a few-shot set — followed by a small varying question. Unlike the gateway cache, this one still calls the provider and still generates a fresh completion. It reduces the cost of the input tokens, not the call.Marking a prefix
Add acache_control marker to the content you want cached. MeshAPI forwards it to providers that support server-side prompt caching.
Where markers are honoured
Whethercache_control reaches the provider depends on which provider serves the model, not on the model name alone. The same model can behave differently depending on how it is routed.
OpenAI’s direct API performs prompt caching automatically on long prompts — you do not mark it, and you cannot control it from here. Markers are removed on that route not because caching is unavailable, but because the provider manages it itself.
Reading the result
Every response tells you exactly what the cache did, underusage.prompt_tokens_details:
prompt_tokens includes both numbers, so the tokens processed fresh at the normal rate are prompt_tokens - cached_tokens - cache_write_tokens.
Every key above is present on every chat completion, whichever provider served it, and is 0 when unused — you can index them directly. Two limits on what a 0 means:
cache_write_1h_tokensis filled only where the serving provider reports the 1h split. A route that doesn’t report it reads0even after a 1h write.- A route that does not report cache writes at all returns
cache_write_tokens: 0.
/v1/responses and /v1/messages, are in the Usage Object reference.
total_tokens is always prompt_tokens + completion_tokens.
On a streaming request the usage block arrives on the final chunk. You do not need to ask for it — MeshAPI requests usage from the provider on every stream, so the cache breakdown is there either way.
What it costs
Cached tokens are not billed at the normal input rate. Every Claude model on MeshAPI uses the same two multipliers:
Measured end to end on
anthropic/claude-sonnet-5 with a 6,800-token system block, same prompt each time:
So a hit costs about an eighth of the uncached call, and the write premium is repaid inside the first hit — two calls sharing a prefix are already ~31% cheaper than two uncached ones.
What decides whether it pays is reuse, not prompt share. A segment costs 1.25× once and 0.10× on every later read, against 1.00× each time uncached — so it is ahead the first time it is read (1.25 + 0.10 < 2.00), however small a fraction of the prompt it is. A 2,000-token prefix on a 50,000-token request still pays, provided it is reused.
Holding a prefix for an hour
The default entry expires after ~5 minutes. If your calls are further apart than that, add a TTL and the prefix survives an hour instead:
Writes made under a 1h TTL are reported separately as
cache_write_1h_tokens in prompt_tokens_details, so you can tell the two apart on the bill.
On Bedrock the TTL applies to Claude models only, and it is all-or-nothing per request: MeshAPI reports the 1h rate only when every breakpoint in the request carries
ttl: "1h". Mix 5m and 1h markers in one call and the whole request bills at the 5m rate. A model whose price row has no 1h rate configured also bills 1h writes at the 5m rate.Multi-turn: move the breakpoint forward
The biggest win is a conversation, not a single call. Each turn resends everything before it, so with one marker pinning the stable head and a second rolling onto the newest message, every turn reads the whole previous turn and writes only the delta.When a marker doesn’t take effect
A marker that does nothing is silent — the request succeeds and returns a normal completion. Ifcached_tokens and cache_write_tokens both come back 0, work down this list:
The cached block is too small
The cached block is too small
Providers refuse to store a prefix below a minimum, and it is model-dependent: 1,024 tokens on Sonnet and Opus, 2,048 on Haiku. Under it you get no cache entry and no error. MeshAPI does not validate this for you.
Your tool list changed
Your tool list changed
Tool definitions sit ahead of the system block in the cached prefix, so editing, adding or removing a tool invalidates everything after it. Measured: the same system block with one extra tool schema returned
cached_tokens: 0 and re-wrote all 7,153 tokens. Keep tools byte-stable across the calls meant to share a prefix — including the order of the array.More than five minutes passed
More than five minutes passed
A default
ephemeral entry lives about 5 minutes, refreshed each time it is read. A loop that idles longer between turns pays the write again and again and never collects the discount — see Holding a prefix for an hour.You trimmed the conversation from the front
You trimmed the conversation from the front
Dropping the oldest messages to stay under a limit changes the start of the prompt, which is exactly what the cache keys on — so nothing after it can be reused. Summarize into the system block instead of dropping the head — otherwise every trim turns that turn’s write into one that is never read.
The route doesn't honour markers
The route doesn't honour markers
See Where markers are honoured — direct OpenAI, Together, DeepInfra, Qwen and Vertex strip the field, and Bedrock applies it only to Claude and Nova. Check which provider actually served the request in your usage records.
A request that fails upstream does not warm the cache, so a rejected call costs you nothing in cache writes — the next valid call is a normal cold write.
Choosing between them
- Repeating identical requests (dashboards, evals, retries, deterministic pipelines) → the gateway cache does this for free, automatically. Just keep
temperatureat0. - Varying questions over a large fixed context (document Q&A, long system prompts, few-shot, agent loops) → the gateway cache never hits, because the messages differ every time. Use provider prompt caching: the prefix is reused on every question, which is exactly when it pays.
- Prompts with nothing stable in them (each call unique, or calls further apart than the TTL) → neither. A marker here is written and never read, which costs 25% more than not caching.
- Both are valid together: a repeated request hits the gateway cache first and never reaches the provider at all.
Related
- Memory — why memory-attached requests bypass the response cache
- Usage & Monitoring API — measuring hit rate and savings
- Usage Object — every
usagefield, and which cache counts each provider reports - Pricing — how cached tokens are billed