Migrating from OpenRouter to Ringside
OpenRouter sells tokens. Ringside sells Customers. Same
base_urlshape, same 100+ models behind one key. The difference: per-end-customer billing attribution, budget caps, webhooks, Client Tokens, margin reporting, and a proper conversation persistence layer. None of which OpenRouter ships. Switch in 60 seconds.
Status: v1 (2026-04-20).
See also: Migration library index.
TL;DR: one-character diff (plus a prefix)
Python
python# Before (OpenRouter) from openai import OpenAI client = OpenAI( api_key="sk-or-v1-...", base_url="https://openrouter.ai/api/v1", ) resp = client.chat.completions.create( model="anthropic/claude-3.5-sonnet", messages=[{"role": "user", "content": "Hello"}], ) # After (Ringside) client = OpenAI( api_key="ko_...", base_url="https://api.fightclub.pro/v1", ) resp = client.chat.completions.create( model="fc:anthropic/claude-sonnet-4-5", # add the fc: prefix messages=[{"role": "user", "content": "Hello"}], user="cus_42", # <- attribution you didn't have )
One URL swap, one fc: prefix, one user field. Done.
Node.js / TypeScript
javascript// Before const openai = new OpenAI({ apiKey: process.env.OPENROUTER_API_KEY, baseURL: "https://openrouter.ai/api/v1", }); // After const openai = new OpenAI({ apiKey: process.env.RINGSIDE_API_KEY, baseURL: "https://api.fightclub.pro/v1", }); const resp = await openai.chat.completions.create({ model: "fc:anthropic/claude-sonnet-4-5", messages: [{ role: "user", content: "Hello" }], user: "cus_42", });
Why migrate
OpenRouter is a great multi-provider aggregator. It's missing one category of feature, and it's the one that matters when you're building a real product:
- Per-end-customer billing attribution. OpenRouter shows you a single total. It has no concept of "which of my end-customers caused this spend." You have to build that yourself: every call, correlate with your own user ID, store usage events, aggregate. That's a database schema, a pipeline, and a dashboard you're maintaining. Ringside's
user: "cus_42"does all of it, server-side, zero code from you. - Budget caps. OpenRouter has credit caps at the account level. Ringside has budget caps per Customer:
PATCH /v1/customers/cus_42 {monthly_budget_usd: 50}. Hit $50, Ringside returns402 customer_budget_exceeded. Your runaway-loop horror story dies in its sleep. - Webhooks. 13 event types (
customer.budget_exceeded,wallet.low,run.failed,moderation.flagged, etc.). HMAC-signed, retried. OpenRouter has none. - Client Tokens. Short-lived Ed25519-signed JWTs pinned to a Customer, optional Origin allowlist, optional IP hash. Let browsers call
chat/completionsdirectly without going through your backend. OpenRouter can't safely do this. - Conversation persistence. Ringside stores threads + messages + runs server-side. You don't need a Postgres schema for chat history.
- Margin reporting.
X-FC-Billable-Amount: 0.25on the call →GET /v1/marginshows what you charged vs. what it cost. Run your pricing experiments with real data.
Step-by-step (60 seconds)
- Sign up at
ringside.fightclub.pro/register?intent=ringside. $10 credit, no card. - Create a server token at
/ringside/app/api-keys/new. - Update your SDK init:
base_url = "https://api.fightclub.pro/v1",api_key = "ko_...". - Rewrite your model string:
anthropic/claude-3.5-sonnet→fc:anthropic/claude-sonnet-4-5. (Ringside uses the provider's canonical current model name; our/v1/modelsendpoint lists all 250+.) - Add
user: "<your-end-customer-id>"to every call.
Drop-in code diffs
Streaming
pythonstream = client.chat.completions.create( model="fc:openai/gpt-4o-mini", messages=[{"role": "user", "content": "Stream a poem"}], stream=True, user="cus_42", ) for chunk in stream: print(chunk.choices[0].delta.content or "", end="", flush=True)
Ringside emits OpenAI chat-completion-chunk format byte-exact across all 19 providers (C.6 canonical SSE layer). Same shape OpenRouter emits today, no parser change.
Tool calling with multi-provider fallback
python# Ringside slot alias — re-pointable without code changes resp = client.chat.completions.create( model="slot:chat-fast", messages=[{"role": "user", "content": "What's the weather in SF?"}], tools=[{ "type": "function", "function": { "name": "get_weather", "parameters": { "type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"], }, }, }], user="cus_42", )
Slot aliases (slot:<name>) resolve via platformSettings.slotAliases. You can swap slot:chat-fast from fc:openai/gpt-4o-mini to fc:groq/llama-3.1-70b in the dashboard without redeploying.
Attribution via headers (recommended for multi-tag setups)
pythonclient.chat.completions.create( model="fc:openai/gpt-4o-mini", messages=[{"role": "user", "content": "Hello"}], user="cus_42", extra_headers={ "FC-Tag": "support-bot", "FC-Property-Plan": "enterprise", "X-FC-Billable-Amount": "0.50", # what you charged your customer for this call }, )
Then query margin:
bashcurl -H "Authorization: Bearer ko_..." \ "https://api.fightclub.pro/v1/customers/cus_42/margin?group_by=day"
Feature mapping
| OpenRouter | Ringside equivalent |
|---|---|
openrouter.ai/api/v1/chat/completions | api.fightclub.pro/v1/chat/completions |
model: "anthropic/claude-3.5-sonnet" | model: "fc:anthropic/claude-sonnet-4-5" (add fc: prefix) |
HTTP-Referer / X-Title headers | Optional FC-Tag / FC-Property-* headers for richer metadata |
| Account-level credit cap | Per-Customer + global budget caps |
Transforms (transforms: ["middle-out"]) | Not v1, most use cases solved by max_tokens + model choice |
Auto-routing (model: "openrouter/auto") | Not v1 (v2 target, slot: aliases give you manual failover today) |
provider: {order: [...]} preference | Use explicit fc:<provider>/<model> per-call |
| Usage dashboard | GET /v1/usage, /margin, /customers/:id/usage + /ringside/app/usage UI |
| n/a | Customer Object + per-Customer budgets |
| n/a | Webhooks (13 events) |
| n/a | Client Tokens (frontend-safe JWTs) |
| n/a | Conversation persistence (/v1/customers/:id/conversations) |
| n/a | Assistants API wire-compat (for migrating from OpenAI Assistants) |
| n/a | Margin reporting (your charge vs. Ringside cost) |
Gotchas
- Pricing shape differs. OpenRouter's markup is roughly ~5% flat. Ringside's is 6% (Pro) or 10% (Developer), plus the Pro tier's $99/mo base. Compare your monthly volume + how much you value the features OpenRouter doesn't ship. Rough break-even: if you'd spend an engineer-week building Customer attribution, Ringside Pro is cheaper in year one.
- Model naming. Ringside uses
fc:<provider>/<current_name>. OpenRouter sometimes lags the provider's current naming (e.g.claude-3.5-sonnetvs.claude-sonnet-4-5). CheckGET /v1/modelsfor the canonical Ringside name. - No auto-routing in v1. OpenRouter's
openrouter/autoroutes to cheapest-matching. Ringside v2 will add this (§22 in the v1 API spec). For now, useslot:<alias>indirection. You pick the target; we make it re-pointable. - No provider-order preference in v1. OpenRouter lets you prefer Azure OpenAI over OpenAI direct, etc. Ringside v1 pins each
fc:<provider>/<model>to a single upstream. v2 will add preference lists. - Transforms (middle-out, etc.) not supported. The common use case (long-context truncation) is handled by Ringside's conversation-context truncation on
/v1/conversations/*/messages+ explicitmax_tokens. HTTP-RefererandX-Titleheaders. OpenRouter uses these for its public leaderboard. Ringside ignores them; we don't have a public leaderboard (privacy-by-default). UseFC-Property-*if you want the metadata attached to UsageEvents.
FAQ
Q: Can I use all 250+ models OpenRouter has? A: Ringside covers 19 providers, roughly 100+ models today, with the rest coming in v1.1. Hit GET /v1/models for the current list. If a model you need isn't there, email support@fightclub.pro and we'll add it.
Q: What about prompt caching across providers? A: OpenAI automatic caching + Anthropic cache_control blocks both work. Ringside's C.6 canonical usage layer reports cached_input_tokens uniformly.
Q: Is Ringside faster than OpenRouter? A: Comparable. Both add roughly 10-30ms edge overhead on top of the upstream provider. Streaming first-byte is unaffected.
Q: Do I get a Customer-level dashboard? A: Yes. /ringside/app/customers/[id] shows per-Customer conversations, usage, budget status, webhooks, and Client Tokens in one view.
Q: Can I run OpenRouter and Ringside side-by-side? A: Yes. Route a percentage of traffic to each, compare. Since both speak OpenAI wire format, your client code branches on one base_url variable.
Next steps
- Try in the no-signup playground.
- Model catalog:
ringside.fightclub.pro/docs/models. - Support:
support@fightclub.proor Discord#migration.
Related migrations
- OpenAI Chat Completions → Ringside
- OpenAI Assistants → Ringside
- Anthropic Messages → Ringside
- Chatbase → Ringside
- Index
Corrections, feedback: chka@stratus5.com.