Anthropic API from Russia: moving your code and Claude Code to Zukko

Anthropic SDK code and Claude Code move to the gateway with an address and key change. Where the /v1 trap is, which Claude models are available, and how caching works.

6 min · · development · IDE

What stops people from using the Anthropic API from Russia isn't code, it's payment: you can't attach a local card to the Anthropic console. Zukko accepts requests in native Anthropic format, so the Anthropic SDK and Claude Code move over with an address and key change, and prompt caching keeps saving you money. Below: the changes for Python, TypeScript and Claude Code, a table of Claude models, and a cost calculation with caching.

What stays the same

Zukko is an API gateway to Claude, GPT, Gemini, DeepSeek, Qwen and GLM models with a single fetch_... key and a balance in dollars. For the Anthropic format it offers:

  • POST https://api.zukko.pro/v1/messages — the main endpoint;
  • POST https://api.zukko.pro/v1/messages/count_tokens — token counting before a request.

The official Anthropic SDK stays the same. Authentication works both via the x-api-key header (which is what the SDK sends) and via Authorization: Bearer. The SDK sets the anthropic-version: 2023-06-01 header itself.

Anthropic API from Russia: code changes

Python

bash
import os

import anthropic

client = anthropic.Anthropic(
    base_url="https://api.zukko.pro",
    api_key=os.environ["ZUKKO_API_KEY"],  # a fetch_... key
)

message = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain idempotency with an example"}],
)
for block in message.content:
    if block.type == "text":
        print(block.text)

The main trap is the address. base_url goes without /v1: the SDK appends /v1/messages itself. If you add /v1, requests go to /v1/v1/messages and return 404.

Parse the response by block type rather than reading content[0].text: if the model has reasoning enabled, the first block may be of type thinking.

TypeScript

bash
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  baseURL: "https://api.zukko.pro",
  apiKey: process.env.ZUKKO_API_KEY,
});

const message = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Explain idempotency" }],
});

for (const block of message.content) {
  if (block.type === "text") console.log(block.text);
}

Via environment variables

The SDKs read the address from ANTHROPIC_BASE_URL and the token from ANTHROPIC_AUTH_TOKEN (sent as Authorization: Bearer). Then you can create the client with no arguments:

bash
export ANTHROPIC_BASE_URL=https://api.zukko.pro
export ANTHROPIC_AUTH_TOKEN=fetch_your_key
bash
client = anthropic.Anthropic()

If an old Anthropic key (sk-ant-...) is still in your environment, remove it so the SDK doesn't send the old key to the gateway alongside or instead of the new token.

Claude models: names and prices

Model IDs on Zukko match the familiar Claude names. Prices as of October 6, 2026, $ per 1M tokens:

ModelInput / outputCache read / writeVendor price input / outputIntelligence index
claude-opus-5-50.4 / 20.038 / 0.4254 / 2058
claude-fable-5-13.48 / 17.40.3 / 3.66310 / 5053
claude-opus-50.425 / 2.1130.05 / 0.5385 / 25—
claude-sonnet-50.2 / 1.0130.025 / 0.252 / 10—
claude-sonnet-4-60.263 / 1.2750.038 / 0.3253 / 15—

All five have a 1M-token context and accept images. The intelligence index is the Artificial Analysis Intelligence Index shown in the Zukko catalog; a dash means no value is listed. If your code names a model that isn't in the catalog, the request returns 404 model_not_found — switch to one that is. For the current list and prices, see GET https://api.zukko.pro/v1/models or the Models page in your dashboard.

You can also call other vendors' models through /v1/messages, such as gpt-6.1-sol or deepseek-v4.1-flash: the gateway converts the format. Your Anthropic SDK code stays the same — only the model name changes.

Prompt caching works in Anthropic format

For Claude, the cache discount comes from the Anthropic format specifically: the gateway sees how much input came from cache and bills those tokens at the cache read price. In OpenAI format (/v1/chat/completions) all Claude input is billed at the input price. So if you already use cache_control, stay on the Anthropic SDK. The difference between the two formats in numbers is in the article on Claude caching in Messages and Chat Completions.

bash
LONG_INSTRUCTIONS = open("instructions.md", encoding="utf-8").read()

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    system=[{
        "type": "text",
        "text": LONG_INSTRUCTIONS,
        "cache_control": {"type": "ephemeral"},
    }],
    messages=[{"role": "user", "content": "Review this contract for risks: ..."}],
)
u = response.usage
print("fresh input:", u.input_tokens)
print("cache read:", u.cache_read_input_tokens)
print("cache write:", u.cache_creation_input_tokens)
print("output:", u.output_tokens)

A prefix that's too short won't be cached — Anthropic sets the minimum length, and it depends on the model. If cache_read_input_tokens stays at zero on repeated requests, check whether the start of your prompt changes (a date, a random ID).

Worked example: what caching does for an agent session

Formula: cost = fresh input × input price + cache read × read price + cache write × write price + output × output price.

Example for claude-sonnet-5: over a session the agent sent 1,000,000 input tokens, of which 900,000 were read from cache, 50,000 were written to cache and 50,000 were fresh input; output was 100,000 tokens.

  • Fresh input: 50,000 × $0.2 / 1M = $0.01
  • Cache read: 900,000 × $0.025 / 1M = $0.0225
  • Cache write: 50,000 × $0.25 / 1M = $0.0125
  • Output: 100,000 × $1.013 / 1M = $0.1013
  • Total in Anthropic format: $0.1463

The same session in OpenAI format, where all Claude input is billed at the input price: 1,000,000 × $0.2 / 1M + $0.1013 = $0.2 + $0.1013 = $0.3013. The cache share varies between real sessions — check your own numbers in usage.

Claude Code through Zukko

Claude Code appends /v1 itself, so the address goes without the suffix. The key is passed via ANTHROPIC_AUTH_TOKEN:

bash
export ANTHROPIC_BASE_URL=https://api.zukko.pro
export ANTHROPIC_AUTH_TOKEN=fetch_your_key
export ANTHROPIC_MODEL=claude-sonnet-5
claude

To avoid exporting variables every session, put them in the env block of ~/.claude/settings.json, as described in the Claude Code docs:

bash
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.zukko.pro",
    "ANTHROPIC_AUTH_TOKEN": "fetch_your_key",
    "ANTHROPIC_MODEL": "claude-sonnet-5"
  }
}

Claude Code works in Anthropic format, so in long sessions the prompt cache is billed at the cache read price. If Claude Code still asks you to log in to an Anthropic account, see the article on Claude Code asking for an Anthropic login. Full instructions are in the Claude Code docs.

Counting tokens before a request

count_tokens works the same way as on Anthropic and helps estimate the cost of a long document up front:

bash
count = client.messages.count_tokens(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": LONG_INSTRUCTIONS}],
)
print(count.input_tokens, "tokens, input ≈ $", count.input_tokens * 0.2 / 1_000_000)

More in the count_tokens reference.

Migration checklist

  1. Create a key on the API keys page, set a daily limit and allowed models.
  2. In the SDK, set base_url="https://api.zukko.pro" — without /v1.
  3. Use your fetch_... key and remove the old sk-ant-... key from your environment.
  4. Check model names against GET /v1/models.
  5. Parse content by block type.
  6. For Claude Code, set ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN and ANTHROPIC_MODEL.
  7. Confirm in usage that cache_read_input_tokens grows on repeated requests.

The balance can be topped up from $1: SBP and Russian bank cards in rubles at the market rate, cryptocurrency, or a foreign Mastercard EU card with a fee of about 13%.

FAQ

Why is the Anthropic SDK address without /v1 while the OpenAI SDK one has /v1?

The Anthropic SDK and Claude Code append /v1/messages to the base address themselves. The OpenAI SDK only appends chat/completions, so it needs https://api.zukko.pro/v1.

Should I set ANTHROPIC_MODEL in Claude Code?

It's best to set it explicitly, for example claude-sonnet-5 for everyday work or claude-opus-5-5 for hard tasks. Which model handles your project better is something to check on a few real tasks.

Does prompt caching work the same as on Anthropic?

Yes, in Anthropic format: the cache_control markup is the same, and usage shows cache reads and writes. Reads and writes are billed at their own prices from the table.

What should I do about a 402 error?

It means insufficient balance. Top up in the dashboard — from $1, including via SBP.

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_*

Anthropic API from Russia: SDK and Claude Code via a gateway · Zukko