Ringside · Migration guide

Persona · Team Lead Tanya

Updated 2026-04-20

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

  1. Per-end-customer billing. Anthropic's console shows one number: your total spend. Ringside's user: "cus_42" auto-creates a tracked Customer; query GET /v1/customers/cus_42/usage and bill your customers however you want.
  2. 19 providers, one SDK. You keep Claude as your primary model but add fallback, specialization, and cost-optimization paths without rewriting client code.
  3. Webhooks. customer.budget_exceeded, wallet.low, run.failed, moderation.flagged, and 9 more. Anthropic has no webhook surface.
  4. Client Tokens for browser-safe calls. Short-lived Ed25519-signed JWTs that browsers can use to call chat/completions directly without proxying through your backend. Pin to a specific Customer + optional Origin allowlist.
  5. 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)

  1. Sign up at ringside.fightclub.pro/register?intent=ringside. $10 credit, no card.
  2. Create a server token at /ringside/app/api-keys/new.
  3. 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.
  4. Swap your client: base_url="https://api.fightclub.pro/v1", model prefix fc:anthropic/.
  5. Pass user: "<your-end-customer-id>" on every call to get attribution.

Wire-shape diff: Anthropic Messages → OpenAI Chat Completions

Anthropic Messages APIOpenAI 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 responsetool_calls on choices[0].message
cache_control: {"type": "ephemeral"} on blocksPassthrough 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)

python
resp = 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

python
resp = 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 featureRingside equivalent
api.anthropic.com/v1/messagesapi.fightclub.pro/v1/chat/completions + fc:anthropic/* model ref
system: top-levelmessages[0] with role: "system"
max_tokens (required)max_tokens (optional, default 1024)
Native tool useOpenAI-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 APINot in v1 (v2 target)
PDF supportimage_url with data URL for now; native PDF in v2
Console usage reportsGET /v1/usage, /v1/margin, /v1/customers/:id/usage
n/aCustomer Object + budgets + webhooks + Client Tokens

Gotchas

  • max_tokens is optional on Ringside. Anthropic requires it; Ringside defaults to 1024 if omitted. If your Anthropic code always passes max_tokens, keep passing it.
  • Finish-reason renaming. Anthropic end_turn → OpenAI stop; tool_usetool_calls; max_tokenslength. Ringside's C.6 finish-reason translator handles this. If you switch on finish_reason, update the case labels.
  • Token accounting. Ringside's usage.cached_input_tokens = cache_creation_input_tokens + cache_read_input_tokens from Anthropic. If you need the split, it's available in the Ringside request log (/ringside/app/logs) as raw_upstream_usage.
  • System prompt placement. Anthropic has a top-level system param; 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 in usage.reasoning_tokens; the text itself is not returned in v1 (v2 will add a thinking response field).
  • response_format: json_schema is 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 returns 400 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

Related migrations


Corrections, feedback: chka@stratus5.com.