Key facts
| Anthropic endpoint | POST /v1/messages with an x-api-key header |
| Plugsky endpoint | POST https://api.plugsky.com/v1/chat/completions with Authorization: Bearer sk-live-… |
| System prompt | Anthropic's top-level system parameter becomes a system role message |
| Tool schema | input_schema becomes function.parameters in the OpenAI tools array |
| Streaming | content_block_delta events become choices[0].delta.content chunks |
| Model mapping | 30+ models to map Claude tiers onto; verify plugsky-frontier, plugsky-pro or plugsky-lite on your evals |
| Feature gaps | Prompt-cache controls and extended-thinking blocks have no direct equivalent — strip them in the adapter |
| Product status | Live (chat, streaming, tools, JSON mode, embeddings); audio, images, batch and fine-tuning are coming soon |
TL;DR
- The messages array is similar; the system prompt moves inside it.
- Tools need a wrapper: input_schema becomes function.parameters.
- Streaming event names differ but the token stream is equivalent.
- max_tokens is required on Anthropic and optional on Plugsky.
- Prompt caching and extended thinking have no direct equivalent — plan around them.
How it works, step by step
- Inventory every Anthropic call site and note which features it uses (tools, vision, caching, thinking).
- Create a Plugsky API key and confirm access with a single chat completion.
- Map Claude models to Plugsky models and write an adapter that converts messages and tools.
- Replace the Anthropic SDK with the OpenAI SDK pointed at https://api.plugsky.com/v1.
- Convert streaming consumers from content_block_delta to delta.content chunks.
- Run your eval suite against both providers and diff the outputs.
- Cut over traffic gradually and keep the adapter reversible for one release cycle.
Original data
Try it yourself
Open the OpenAI migration checker →
How the Anthropic API differs
Four differences cause most migration bugs:
- Auth: Anthropic sends
x-api-key: sk-ant-…; Plugsky sendsAuthorization: Bearer sk-live-…. - System prompt: Anthropic takes a top-level
systemstring; OpenAI-compatible APIs use a message withrole: "system". - Tools: Anthropic tools use
input_schema; Plugsky usesfunction.parametersinside a{"type": "function", "function": {…}}wrapper. - Streaming: Anthropic emits named events such as
content_block_deltawithtext_delta; Plugsky emits OpenAI chunks withchoices[0].delta.content.
Everything else — multi-turn history, temperature, stop sequences, tool result turns — maps directly.
Step-by-step conversion
An Anthropic call:
import anthropic
client = anthropic.Anthropic(api_key="sk-ant-…")
msg = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
system="You are a terse support agent.",
messages=[{"role": "user", "content": "How do refunds work?"}],
)The Plugsky equivalent:
from openai import OpenAI
client = OpenAI(api_key="sk-live-…", base_url="https://api.plugsky.com/v1")
resp = client.chat.completions.create(
model="plugsky-pro",
max_tokens=1024,
messages=[
{"role": "system", "content": "You are a terse support agent."},
{"role": "user", "content": "How do refunds work?"},
],
)
print(resp.choices[0].message.content)Keep an adapter function so the mapping lives in one place. It should accept Anthropic-shaped input and return an OpenAI-shaped request; that lets you A/B both providers during migration.
Converting tools and streaming
Tool conversion is mechanical. Anthropic:
{"name": "get_weather", "description": "Get weather",
"input_schema": {"type": "object", "properties": {"city": {"type": "string"}}}}Plugsky and other OpenAI-compatible endpoints:
{"type": "function",
"function": {"name": "get_weather", "description": "Get weather",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}}}}Tool choice moves from {"type": "tool", "name": "get_weather"} to {"type": "function", "function": {"name": "get_weather"}}. For streaming, replace handlers that listen for content_block_delta with a loop over chunks and append chunk.choices[0].delta.content when it is present. Anthropic's content_block_start and message_delta events have no direct equivalents, so usage accounting moves to the final chunk or a non-streaming call.
What to validate before cutover
Run your eval suite on both providers with identical prompts. Score three things: task success, tool-call correctness and output format. Watch for workloads that depend on features Plugsky does not replace today — prompt caching and extended thinking are the two that force architectural changes, because the cache-control blocks must be stripped before the request is sent.
For high-volume workloads, route cheap classification steps and hard reasoning steps to different Plugsky models instead of one Claude tier. plugsky-lite handles extraction and routing; plugsky-pro or plugsky-frontier handle synthesis. Because Plugsky is OpenAI-compatible, you can keep the adapter in place and switch providers by changing one base URL if an eval regresses.
Honest comparison
| Capability | Plugsky (OpenAI-compatible) | Anthropic Messages API | Dual-provider router |
|---|---|---|---|
| Auth | Bearer sk-live-… | x-api-key header | Two credential types |
| System prompt | system role message | Top-level system field | Adapter maps both |
| Tools | functions in the tools array | input_schema in the tools array | Translate schemas at the boundary |
| Streaming | choices[].delta.content | content_block_delta events | Normalize both formats |
| Unique features | Flat plans, fusion model, residency options | Prompt caching, extended thinking | Keep both providers for now |
| Migration effort | Rewrite calls to the OpenAI SDK plus an adapter | Incumbent | Ongoing maintenance burden |
Frequently asked questions
Can I keep using the Anthropic SDK?
No. The Messages API is not OpenAI-compatible, so you switch to an OpenAI-compatible client and convert request shapes in an adapter.
Where does the system prompt go?
Move the top-level system string into the first message with role: "system" in the messages array.
How do I convert tools?
Wrap each tool as {"type": "function", "function": {...}} and rename input_schema to parameters. Tool choice uses the same wrapper.
How does streaming change?
Read chunk.choices[0].delta.content instead of listening for content_block_delta events. Usage moves to the final chunk.
Is max_tokens required?
No. Anthropic requires max_tokens; on Plugsky it is optional, though setting it explicitly helps control cost and latency.
What Claude features do not carry over?
Prompt-cache controls and extended-thinking blocks have no direct equivalent today. Strip them in the adapter and re-evaluate those workloads.
How should I pick Plugsky models?
Map Claude tiers to plugsky-pro or plugsky-frontier for complex work and plugsky-lite for high-volume steps, then validate on your evals.
Can I run both providers side by side?
Yes. Keep a provider switch behind one adapter and route a small share of traffic to Plugsky while you compare quality and cost.