Claude via /v1/messages or /v1/chat/completions: what happens to caching

Claude answers in both formats, but only the Anthropic format gives the cache discount. The cost difference and how to switch your code and tools.

5 min · · экономия · development

Many people connect the Claude API through the OpenAI-compatible format: the SDK is already installed, the code is written around chat.completions, and nobody wants to change it. It works, but for Claude that setup has a price — prompt caching is not counted in it. Let's look at where the difference matters, what it costs in money, and how to move your code and tools to the Anthropic format.

Two formats, one key

Zukko accepts requests in two formats:

  • OpenAI-compatible — POST https://api.zukko.pro/v1/chat/completions (and /v1/responses);
  • Anthropic-compatible — POST https://api.zukko.pro/v1/messages.

The fetch_... key and the balance are shared. Any model can be called in either format — the gateway converts requests and responses. The difference is not which models are available but how caching is billed.

Claude API in the OpenAI-compatible format: what happens to caching

The rule is short:

  • in the Anthropic format (/v1/messages, Claude Code, the Anthropic SDK) the gateway sees how much input came from cache and bills those tokens at the cache read price;
  • in the OpenAI format (/v1/chat/completions) all Claude input is billed at the input price.

For short one-off requests there is no difference: there is nothing to cache. It shows up where a long beginning repeats from request to request — agents, bots with large instructions, work over the same document.

What it costs

An agent step on claude-sonnet-5: 100,000 tokens of context, of which 95,000 is the repeating beginning and 5,000 is new; a 2,000-token answer. Zukko prices per 1M tokens: input $0.2, cache read $0.025, output $1.013.

Through /v1/messages, if the beginning is read from cache:

(95,000 × 0.025 + 5,000 × 0.2 + 2,000 × 1.013) / 1,000,000 = (2,375 + 1,000 + 2,026) / 1,000,000 = $0.005401

Through /v1/chat/completions, all input at the input price:

(100,000 × 0.2 + 2,000 × 1.013) / 1,000,000 = (20,000 + 2,026) / 1,000,000 = $0.022026

Over 200 such steps: $1.0802 versus $4.4052. The calculation is simplified: in a real session some steps also write new chunks of context to the cache, and a write on Claude Sonnet 5 costs $0.25 per million. The usage field in responses and the Usage section of the dashboard show the exact picture. The full formula with writes and reads is in the article on how cache reads and writes are billed.

How to switch your code to the Anthropic SDK

Before — the OpenAI SDK:

bash
from openai import OpenAI

client = OpenAI(base_url="https://api.zukko.pro/v1", api_key="fetch_your_key")

resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": question},
    ],
)
print(resp.choices[0].message.content)

After — the Anthropic SDK (pip install anthropic):

bash
import anthropic

client = anthropic.Anthropic(base_url="https://api.zukko.pro", api_key="fetch_your_key")

resp = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=2048,
    system=[{
        "type": "text",
        "text": SYSTEM_PROMPT,
        "cache_control": {"type": "ephemeral"},
    }],
    messages=[{"role": "user", "content": question}],
)
print("".join(block.text for block in resp.content if block.type == "text"))
print("from cache:", resp.usage.cache_read_input_tokens,
      "written:", resp.usage.cache_creation_input_tokens)

What changes:

  1. Base URL without /v1 — the Anthropic SDK adds /v1/messages itself.
  2. System prompt — a separate system parameter, not a message with the system role.
  3. max_tokens is required.
  4. Response — a list of content blocks; text is assembled from blocks of type text.
  5. Cache marker — cache_control on the stable part. Without it, caching will not kick in for your own code. Per Anthropic's documentation, the minimum cacheable prefix is 1,024 tokens for Claude Sonnet 5 and 512 for Claude Opus 5.5.

If your code uses tools (function calling), you will have to port that too: in the Anthropic format, tool calls and results are tool_use and tool_result blocks inside messages rather than separate fields. This is the most laborious part of the migration; start with the calls where the context is long and repetitive.

You can test without an SDK using curl:

bash
curl https://api.zukko.pro/v1/messages \
  -H "Authorization: Bearer fetch_your_key" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 512,
    "messages": [{"role": "user", "content": "Hello"}]
  }'

How to switch your tools

ToolFormat for ClaudeBase URL
Claude CodeAnthropichttps://api.zukko.pro
Roo CodeAnthropic provider, enable Use custom base URLhttps://api.zukko.pro
OpenCodeanthropic providerhttps://api.zukko.pro/v1
Cline, Kilo CodeOpenAI Compatible in our guidehttps://api.zukko.pro/v1
CursorOpenAI format onlyhttps://api.zukko.pro/v1

Claude Code already works in the Anthropic format and places cache markers itself. It needs two variables: ANTHROPIC_BASE_URL=https://api.zukko.pro and ANTHROPIC_AUTH_TOKEN=fetch_... (AUTH_TOKEN specifically).

OpenCode connects through the anthropic provider, but here the address includes /v1 — without it requests go to /messages and get a 404. A config example is in the OpenCode guide.

Roo Code — the Anthropic provider, a fetch_... key, Use custom base URL enabled, and the address without /v1. If the model you need is not in that provider's list, you are left with OpenAI Compatible — and then Claude input gets no cache discount. Step by step — in the VS Code extensions guide.

Cline is connected through OpenAI Compatible in our guide. Cline's documentation also describes an Anthropic provider with a Use custom base URL option; there you pick the model from its list. If you try that route, enter the address without /v1, as in Roo Code, and check the suffix if you get a 404.

Cursor and Kilo Code work through the OpenAI format in our setup. Claude is available in them, but long context is billed at the full input price.

For GPT, caching is visible in both formats

For GPT models the choice of format does not affect caching. In the OpenAI format the number of tokens read from cache arrives in usage.prompt_tokens_details.cached_tokens and is billed at the cache read price. A cache write is not charged separately for GPT: the first request is billed in full at the input price. Through /v1/messages GPT caching is counted too. So GPT models keep their cache discount in tools that only speak the OpenAI format.

If a tool only supports the OpenAI format and your contexts are long, compare Claude and, for example, gpt-6.1-sol on your own tasks: run the same task and look at the totals in the Usage section. Judge quality by your own results, not by the model name. More on formats — in the docs section Choosing a provider.

How to confirm the discount works

  1. Send the same long request in the Anthropic format twice, less than five minutes apart.
  2. In the first response cache_creation_input_tokens is above zero; in the second, cache_read_input_tokens is.
  3. Compare the X-Zukko-Cost-Micros header (request cost in micro-dollars, present on regular, non-streaming responses) across the two requests.

If you do not have a key yet, create one on the API keys page — one key works in both formats. The current model list and prices are at GET https://api.zukko.pro/v1/models or on the Models page in the dashboard.

FAQ

Does Claude work through /v1/chat/completions at all?

Yes. Requests and responses are correct; it is just that in this format all Claude input is billed at the input price, with no cache discount.

Why does the Anthropic SDK use an address without /v1 while OpenCode uses /v1?

The Anthropic SDK and Claude Code add /v1 to the address themselves. The anthropic provider in OpenCode does not, so the suffix is specified manually.

Do I need the anthropic-version header?

SDKs set it themselves. In manual curl requests add anthropic-version: 2023-06-01.

Can I call GPT through /v1/messages?

Yes, the gateway converts the format for any model. GPT cache reads are counted there as well as in /v1/chat/completions.

zukko

Pay 25×
less

for Claude Code & ChatGPT

One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.

Get API keyDocumentation

api.zukko.pro · fetch_*

Claude API in OpenAI-compatible format: caching · Zukko