Migrating from Anthropic

Switch the Anthropic SDK to this platform — mind the base URL, it has no /v1

Already using the Anthropic SDK? Switching takes two lines, and then you can also call dozens of non-Claude models like GPT, GLM, Grok and DeepSeek (full list: Models).

⚠️ The base URL has no /v1#

The Anthropic SDK appends /v1/messages to the base URL itself. So:

# ❌ wrong: produces /v1/v1/messages
client = Anthropic(base_url="https://jiuye.zsopc.com/v1", ...)

# ✅ right: the SDK builds /v1/messages
client = Anthropic(base_url="https://jiuye.zsopc.com", ...)

One line to remember: the OpenAI SDK takes /v1, the Anthropic SDK doesn't.

What changes (Python)#

No API key yet? Create one at jiuye.zsopc.com/dashboard/keys/new (details in Authentication). Sign-up includes $0.30 of trial credit, enough for every example here.

from anthropic import Anthropic

# straight to Anthropic, before
client = Anthropic(
-    api_key="sk-ant-...",
+    api_key="sk-gpushare-xxx",
+    base_url="https://jiuye.zsopc.com",
)

That's both changes. Everything after client.messages.create(...) stays the same.

What changes (TypeScript)#

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

const client = new Anthropic({
-  apiKey: process.env.ANTHROPIC_API_KEY,
+  apiKey: process.env.PLATFORM_API_KEY,
+  baseURL: "https://jiuye.zsopc.com",
});

What changes (curl)#

- curl https://api.anthropic.com/v1/messages \
+ curl https://jiuye.zsopc.com/v1/messages \
-   -H "x-api-key: sk-ant-..." \
+   -H "x-api-key: sk-gpushare-xxx" \
    -H "anthropic-version: 2023-06-01" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "claude-sonnet-4-6",
      "max_tokens": 1024,
      "messages": [{"role": "user", "content": "Hello"}]
    }'

What you gain#

# GPT via the Anthropic SDK
client.messages.create(model="gpt-5.4", max_tokens=1024, messages=[...])

# GLM
client.messages.create(model="glm-5.1", max_tokens=1024, messages=[...])

# Grok
client.messages.create(model="grok-4-fast-reasoning", max_tokens=1024, messages=[...])

# DeepSeek
client.messages.create(model="deepseek-v3.2", max_tokens=1024, messages=[...])

Gemini coverage: four SKUs — gemini-2.5-flash-lite, gemini-2.5-flash-thinking, gemini-3-flash and gemini-3.1-pro-low — can be called directly with the Anthropic SDK (their upstream speaks the Anthropic protocol natively, no translation needed). Other gemini-* models don't support the Anthropic Messages endpoint yet (Anthropic → Gemini translation is on the roadmap) — use the OpenAI Chat or Gemini Native endpoint for those. Per-model support: compatibility matrix.

Pricing#

Direct from Anthropic vs. here:

ModelDirect from Anthropic ($/1M in/out)Here ($/1M in/out)
claude-opus-4-6$15.00 / $75.00$15.00 / $75.00
claude-sonnet-4-6$3.00 / $15.00$3.00 / $15.00

Every call is itemised at jiuye.zsopc.com/dashboard/usage, and keys are managed at jiuye.zsopc.com/dashboard/keys.

How billing works#

  • One wallet: charges come out of your account balance (a USD wallet) shared by every API key — no key has its own budget pool (per key you only get the allowed_models allowlist, an expiry and enable/disable, for access control and auditing).

  • Hold then settle: each request first deducts an estimate based on the max_tokens upper bound, then settles against real token usage when the turn ends, so only actual usage is booked.

  • Out of balance = HTTP 402, returned in the Anthropic error shape on /v1/messages (note this is a scenario Anthropic itself doesn't have, so clients need to recognise it):

    {"type": "error", "error": {"type": "billing_error", "message": "Insufficient balance. Please top up and try again."}}
    

    When the balance runs out every key fails at once and creating a new key won't help; top up at dflop.top/dashboard/billing (Stripe, $1 minimum, same account and shared balance as jiuye.zsopc.com).

  • Cached pricing: when upstream usage reports cached_tokens, the cached rate is applied automatically — nothing to switch on. For the streaming caveat, see the cache_control Q&A below.

Read this after switching#

1. The anthropic-version header#

You can omit it here — the gateway injects anthropic-version: 2023-06-01 when forwarding upstream and doesn't validate the inbound header. Sending it is harmless (it's ignored), so leave the SDK's automatic value alone and include or omit it as you like with curl.

2. Tools / tool use are compatible#

Identical: input_schema, tool_use and tool_result all keep their names. See Tool calling.

3. Streaming matches Anthropic#

Event formats such as event: content_block_delta and event: message_stop are unchanged. See Streaming.

4. Error format#

Errors from /v1/messages keep the Anthropic shape:

{"type": "error", "error": {"type": "...", "message": "..."}}

5. Always send max_tokens#

The Anthropic SDK requires max_tokens client-side, and calling Claude models with raw curl requires it upstream too. The gateway itself doesn't validate it (when missing, the billing estimate falls back to the model default), but send it anyway for predictable behaviour and controllable pre-charge.

6. Anthropic-specific feature support#

FeatureStatus
Messages API (POST /v1/messages)✅ fully supported
Streaming✅ supported
Tool use✅ supported
Vision (image input)⚠️ depends on the model — check supports_vision in Models (claude-opus-4-6 and gpt-5.4 do; grok-4-fast-reasoning and glm-5.1 don't)
Prompt caching (cache_control)⚠️ dropped on translated paths; supported on the native Claude channel
Computer Use beta❌ not supported
Files API❌ not supported
Batch API❌ not supported

7. Timeouts, automatic retries and rate limits#

  • Built-in failover: on upstream 5xx, timeout or connection failure the gateway retries across available channels, up to 3 attempts per request; if all fail you get the last upstream error. So an individual request can occasionally be slower than going direct to Anthropic — it may already have been retried internally. Use exponential backoff in your own retries and account for this layer so the two don't compound.
  • No available channel: HTTP 503 in the Anthropic shape, {"type": "error", "error": {"type": "overloaded_error", ...}}. Health probing runs every 6 hours, so a persistent 503 means switching model or reporting it — waiting a few minutes won't help.
  • Timeouts: chat endpoints cap the upstream at 180 seconds total (streaming is bound by the same total, it just delivers the first token sooner). Set your SDK timeout to ≥ 200s.
  • Rate limits: there's no hard QPS limit here; a 429 is an upstream limit passed through, so handle it with normal backoff.

Full before/after#

Straight to Anthropic#

import os
from anthropic import Anthropic

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

msg = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a haiku"}],
)
print(msg.content[0].text)

Through this platform#

import os
from anthropic import Anthropic

client = Anthropic(
    api_key=os.environ["PLATFORM_API_KEY"],
    base_url="https://jiuye.zsopc.com",
)

# still Claude
msg = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a haiku"}],
)

# and GPT too — from the Anthropic SDK!
msg_gpt = client.messages.create(
    model="gpt-5.4",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a haiku"}],
)

FAQ#

Should I keep my ANTHROPIC_API_KEY env var?#

Keep both around:

export ANTHROPIC_API_KEY=sk-ant-...       # straight to Anthropic
export PLATFORM_API_KEY=sk-gpushare-...

How do I switch the Claude Code client?#

export ANTHROPIC_BASE_URL=https://jiuye.zsopc.com
export ANTHROPIC_AUTH_TOKEN=sk-gpushare-xxx
claude

See Claude Code.

Q: Can I still use cache_control?#

  • The native Claude channel supports it (Anthropic passed straight through to a Claude model)

  • Translated paths drop the field and tell you so via the X-Protocol-Warning response header, for example:

    X-Protocol-Warning: content[].cache_control dropped
    X-Protocol-Warning: system.cache_control dropped (OpenAI has no equivalent)
    

    That header's value is a human-readable sentence — don't match it exactly; check the header exists and contains the substring cache_control.

If prompt caching matters to your costs, stick to Claude models on /v1/messages and support stays complete.

Streaming cache-discount caveat: Anthropic's upstream message_delta events don't carry cache_read_input_tokens, so with stream: true the gateway can only settle on the visible counts and the cache discount may be under-applied (you pay slightly more than you should). For high-frequency, cache-sensitive workloads, use stream: false (which yields an accurate discount) or reconcile the bill yourself.

How do I tell whether I'm on a native or a translated path?#

Look at the response headers:

  • X-Protocol-Translation: <tag> — translated path
  • header absent — native pass-through

You can also look up every model × endpoint path in the compatibility matrix.

Next steps#

  • Which model gives the best value? See Models § picking by job
  • Want to call Gemini from the Anthropic SDK? gemini-2.5-flash-lite, gemini-2.5-flash-thinking, gemini-3-flash and gemini-3.1-pro-low work directly; other gemini-* models aren't supported yet (on the roadmap) — use the Gemini SDK or OpenAI SDK
  • Non-chat endpoints such as image, video and embeddings: Image / video / music APIs