Migrating from Anthropic Messages API to Ringside
One base URL. All 19 providers. Use Anthropic behind OpenAI's SDK. Keep Claude as your primary model but stop paying the ecosystem tax of being single-vendor. Per-end-customer billing, webhooks, Client Tokens, budget caps, margin reporting: Anthropic doesn't ship any of them, Ringside does.
Status: v1 (2026-04-20).
See also: Migration library index.
TL;DR
You're switching from Anthropic's Messages API (api.anthropic.com/v1/messages) to Ringside's Chat Completions endpoint (api.fightclub.pro/v1/chat/completions), using Anthropic's models via the fc:anthropic/* prefix. The OpenAI SDK becomes your client library. Anthropic-specific features (prompt caching, extended thinking, tool use, vision) all pass through.
python# Before (Anthropic SDK) import anthropic client = anthropic.Anthropic(api_key="sk-ant-...") msg = client.messages.create( model="claude-haiku-4-5", max_tokens=1024, system="You are a helpful assistant.", messages=[{"role": "user", "content": "Hello"}], ) print(msg.content[0].text) # After (OpenAI SDK → Ringside) from openai import OpenAI client = OpenAI( api_key="ko_...", base_url="https://api.fightclub.pro/v1", ) msg = client.chat.completions.create( model="fc:anthropic/claude-haiku-4-5", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello"}, ], user="cus_42", ) print(msg.choices[0].message.content)
Why migrate
- Per-end-customer billing. Anthropic's console shows one number: your total spend. Ringside's
user: "cus_42"auto-creates a tracked Customer; queryGET /v1/customers/cus_42/usageand bill your customers however you want. - 19 providers, one SDK. You keep Claude as your primary model but add fallback, specialization, and cost-optimization paths without rewriting client code.
- Webhooks.
customer.budget_exceeded,wallet.low,run.failed,moderation.flagged, and 9 more. Anthropic has no webhook surface. - Client Tokens for browser-safe calls. Short-lived Ed25519-signed JWTs that browsers can use to call
chat/completionsdirectly without proxying through your backend. Pin to a specific Customer + optional Origin allowlist. - Normalized errors + streaming. One error taxonomy, one SSE chunk shape, regardless of whether the call ends up hitting Anthropic, OpenAI, Bedrock, or anywhere else.
Step-by-step (5 minutes)
- Sign up at
ringside.fightclub.pro/register?intent=ringside. $10 credit, no card. - Create a server token at
/ringside/app/api-keys/new. - Install the OpenAI SDK if you don't already have it (
pip install openai/npm install openai). The Anthropic SDK is not used from here on. - Swap your client:
base_url="https://api.fightclub.pro/v1", model prefixfc:anthropic/. - Pass
user: "<your-end-customer-id>"on every call to get attribution.
Wire-shape diff: Anthropic Messages → OpenAI Chat Completions
| Anthropic Messages API | OpenAI Chat Completions (Ringside) |
|---|---|
system: "..." (top-level string) | messages[0] = {"role": "system", "content": "..."} |
messages: [{"role": "user", "content": "hi"}] | Same shape; content may be string or content-blocks array |
Content blocks: [{"type": "text", "text": "hi"}] | Same array shape supported (OpenAI SDK accepts it) |
max_tokens: 1024 (REQUIRED) | max_tokens: 1024 (optional; default 1024 on Ringside) |
Tool use: tools: [{name, description, input_schema}] | tools: [{"type": "function", "function": {name, parameters, description}}] |
tool_use content blocks on response | tool_calls on choices[0].message |
cache_control: {"type": "ephemeral"} on blocks | Passthrough on fc:anthropic/* refs (C.6 canonical) |
| Vision: image content block with source | {"type": "image_url", "image_url": {"url": "..."}} part |
stream: true (native Anthropic SSE events) | stream: true (OpenAI chat-completion-chunk shape, byte-exact) |
stop_reason: "end_turn" | finish_reason: "stop" |
stop_reason: "tool_use" | finish_reason: "tool_calls" |
stop_reason: "max_tokens" | finish_reason: "length" |
usage: {input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens} | usage: {prompt_tokens, completion_tokens, cached_input_tokens} (Ringside canonical sums both cache fields) |
Full matrix with per-feature status: ringside.fightclub.pro/docs/compatibility.
Drop-in code diffs
Streaming
python# Before (Anthropic SDK) with client.messages.stream( model="claude-haiku-4-5", max_tokens=1024, messages=[{"role": "user", "content": "Count to 10"}], ) as stream: for text in stream.text_stream: print(text, end="", flush=True) # After (OpenAI SDK → Ringside, Anthropic under the hood) stream = client.chat.completions.create( model="fc:anthropic/claude-haiku-4-5", messages=[{"role": "user", "content": "Count to 10"}], stream=True, user="cus_42", ) for chunk in stream: print(chunk.choices[0].delta.content or "", end="", flush=True)
Ringside's canonical SSE layer translates Anthropic's message_start / content_block_delta / message_delta events into OpenAI chat-completion-chunk format on the wire. Your existing OpenAI-style SSE parser works unchanged.
Tool use
python# After (Ringside — Anthropic tools via OpenAI SDK shape) resp = client.chat.completions.create( model="fc:anthropic/claude-sonnet-4-5", messages=[{"role": "user", "content": "What's the weather in SF?"}], tools=[{ "type": "function", "function": { "name": "get_weather", "description": "Get current weather for a location", "parameters": { "type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"], }, }, }], user="cus_42", ) # resp.choices[0].message.tool_calls is OpenAI-shape regardless of underlying provider
Ringside's C.6 canonical tool-call translator rewrites Anthropic tool_use content blocks → OpenAI tool_calls on the way out, and your tool_calls replies → Anthropic tool_result content blocks on the way back in.
Prompt caching (Anthropic-specific, works via passthrough)
pythonresp = client.chat.completions.create( model="fc:anthropic/claude-sonnet-4-5", messages=[ { "role": "system", "content": [ { "type": "text", "text": "<very long instructions 10k tokens...>", "cache_control": {"type": "ephemeral"}, # <- passes through verbatim } ], }, {"role": "user", "content": "Question?"}, ], user="cus_42", ) print(resp.usage) # Ringside canonical: cached_input_tokens = cache_read + cache_creation (summed)
Vision
pythonresp = client.chat.completions.create( model="fc:anthropic/claude-sonnet-4-5", messages=[{ "role": "user", "content": [ {"type": "text", "text": "What's in this image?"}, {"type": "image_url", "image_url": {"url": "https://example.com/cat.jpg"}}, ], }], user="cus_42", )
Ringside rewrites image_url parts into Anthropic's image content-block shape before dispatch.
Feature mapping
| Anthropic feature | Ringside equivalent |
|---|---|
api.anthropic.com/v1/messages | api.fightclub.pro/v1/chat/completions + fc:anthropic/* model ref |
system: top-level | messages[0] with role: "system" |
max_tokens (required) | max_tokens (optional, default 1024) |
| Native tool use | OpenAI-shape tools + tool_calls (C.6 canonical translator) |
cache_control (prompt caching) | Passthrough (C.6 canonical usage aggregation) |
Extended thinking (thinking: {type: "enabled"}) | extra_body={"thinking": {...}} passthrough |
| Vision (image content blocks) | image_url content parts (auto-translated) |
| Batch API | Not in v1 (v2 target) |
| PDF support | image_url with data URL for now; native PDF in v2 |
| Console usage reports | GET /v1/usage, /v1/margin, /v1/customers/:id/usage |
| n/a | Customer Object + budgets + webhooks + Client Tokens |
Gotchas
max_tokensis optional on Ringside. Anthropic requires it; Ringside defaults to 1024 if omitted. If your Anthropic code always passesmax_tokens, keep passing it.- Finish-reason renaming. Anthropic
end_turn→ OpenAIstop;tool_use→tool_calls;max_tokens→length. Ringside's C.6 finish-reason translator handles this. If you switch onfinish_reason, update the case labels. - Token accounting. Ringside's
usage.cached_input_tokens=cache_creation_input_tokens + cache_read_input_tokensfrom Anthropic. If you need the split, it's available in the Ringside request log (/ringside/app/logs) asraw_upstream_usage. - System prompt placement. Anthropic has a top-level
systemparam; OpenAI puts it as the first message. Make sure you move it. Forgetting is the #1 migration bug. - Streaming chunk shape. You'll receive OpenAI's chat-completion-chunk format even though the upstream is Anthropic. If you previously consumed Anthropic's raw event stream (
message_start,content_block_delta), switch to OpenAI's delta-based parser. Most OpenAI SDKs do this for you. - Extended thinking. Pass via
extra_body={"thinking": {"type": "enabled", "budget_tokens": 4000}}. The thinking output is surfaced inusage.reasoning_tokens; the text itself is not returned in v1 (v2 will add athinkingresponse field). response_format: json_schemais fallback-mode on Anthropic. Anthropic has no native JSON schema support. Ringside's C.6 enforcer reinforces the schema in the system prompt and validates the response with Ajv. Up to 2 retries; persistent failure →422 response_schema_validation_failed. Streaming + non-native schema returns400 streaming_with_schema_fallback_unsupported.
FAQ
Q: Does this cost more than Anthropic direct? A: Ringside Pro is a $99/mo base + 6% markup on tokens. On typical workloads (>$1.5k/month token spend), the built-in features (Customer billing, webhooks, budgets, margin reports) replace what would otherwise be a full-time eng-month to build. See /pricing.
Q: Latency? A: ~10–30ms edge overhead. Streaming first-byte is unaffected.
Q: Can I still access Anthropic-specific fields? A: Yes. extra_body={"thinking": ..., "tool_choice": {"type": "tool", "name": "..."}} passes arbitrary JSON through. Raw upstream response is stored in the request log for debugging.
Q: GDPR / CCPA hard-delete? A: DELETE /v1/customers/:id?hard=true purges the Customer and anonymizes UsageEvents.
Q: What happens if Anthropic is down? A: Use slot:<alias> refs. Re-point the slot (via /admin/ringside/slots or PATCH /v1/account/slots/:alias) to fc:openai/gpt-4o-mini or another provider with zero app redeploys. We're building automated failover in v2.
Next steps
- Try in the no-signup playground.
- Compatibility matrix:
ringside.fightclub.pro/docs/compatibility. - Support:
support@fightclub.proor Discord#migration.
Related migrations
- OpenAI Chat Completions → Ringside
- OpenAI Assistants → Ringside
- OpenRouter → Ringside
- Chatbase → Ringside
- Index
Corrections, feedback: chka@stratus5.com.