Migrating from OpenAI Chat Completions to Ringside
Change your
base_url. Add auserfield. Watch your attribution dashboard light up. Three lines of code get you per-end-customer billing, budget caps, webhooks, Client Tokens, margin reporting, and 19 LLM providers behind one SDK. Your existing OpenAI SDK stays as-is.
Status: v1 (2026-04-20).
See also: Migration library index.
TL;DR: the three-line diff
Python
python# Before from openai import OpenAI client = OpenAI(api_key="sk-...") resp = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "Hello"}], ) # After from openai import OpenAI client = OpenAI( api_key="ko_...", # <- your Ringside server token base_url="https://api.fightclub.pro/v1", # <- Ringside endpoint ) resp = client.chat.completions.create( model="fc:openai/gpt-4o-mini", # <- fc:<provider>/<model> ref messages=[{"role": "user", "content": "Hello"}], user="cus_42", # <- your end-customer ID (attribution!) )
Node.js / TypeScript
javascript// Before import OpenAI from "openai"; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); const resp = await openai.chat.completions.create({ model: "gpt-4o-mini", messages: [{ role: "user", content: "Hello" }], }); // 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:openai/gpt-4o-mini", messages: [{ role: "user", content: "Hello" }], user: "cus_42", });
That's the entire migration for the basic flow. Everything else (streaming, tool calls, JSON mode, vision, embeddings, moderations) keeps working unchanged.
Why migrate
If you're calling api.openai.com/v1/chat/completions directly today, four things are probably in your backlog:
- Per-end-customer attribution. Your bill from OpenAI is one number for your whole project. Ringside's
user: "cus_42"body field auto-creates a tracked Customer server-side, so you can queryGET /v1/customers/cus_42/usageany time and bill your customers however you want: subscription, usage-based, flat fee. - Budget caps that actually stop the bleeding. One
PATCH /v1/customers/cus_42 {monthly_budget_usd: 50}sets a hard ceiling. When the next call would exceed $50, Ringside returns402 customer_budget_exceeded. No more 3am $10k runaway-loop alerts. - Webhooks on operational events. Get pushed notifications for
customer.budget_exceeded,wallet.low,run.failed,moderation.flagged, and more. No polling loops. - 19 providers behind one URL. OpenAI, Anthropic, Google, Mistral, Groq, Together, Fireworks, Perplexity, DeepSeek, xAI, Cerebras, SambaNova, Cohere, OpenRouter, Ollama, Azure OpenAI, Bedrock, HuggingFace, Replicate. Change the model ref, not the SDK.
Step-by-step (5 minutes)
- Sign up at
ringside.fightclub.pro/register?intent=ringside. Every signup gets $10 one-time credit, no card required. - Create a server token at
/ringside/app/api-keys/new. Copy theko_...token (shown once; if you lose it, rotate). - Point your SDK at
https://api.fightclub.pro/v1and swap the key. - Pass
user: "<your-end-customer-id>"on every call. It can be any stable opaque string (UUID, internal ID, tenant ID). Ringside auto-creates the Customer on first pass. - Deploy. Hit
/ringside/appto watch usage light up per Customer in real-time.
Drop-in code diffs
Streaming chat completions
python# Works identically to OpenAI — just the base_url + model ref change stream = client.chat.completions.create( model="fc:openai/gpt-4o-mini", messages=[{"role": "user", "content": "Write me a haiku"}], stream=True, user="cus_42", ) for chunk in stream: print(chunk.choices[0].delta.content or "", end="", flush=True)
Ringside emits byte-exact OpenAI chat-completion-chunk shape across all 19 providers (see the C.6 canonical streaming layer). Your existing SSE parser doesn't change when you switch providers.
Embeddings
pythonemb = client.embeddings.create( model="fc:openai/text-embedding-3-small", input=["hello", "world"], user="cus_42", )
Moderations (free tier)
pythonmod = client.moderations.create( model="fc:openai/omni-moderation-latest", input="Check this text", ) # Ringside routes moderations through its platform OpenAI key at-cost (no markup on Pro+).
Tool calling
pythonresp = client.chat.completions.create( model="fc:openai/gpt-4o", 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", )
Tools pass through verbatim on OpenAI-compatible providers. On Anthropic/Google/Cohere/Bedrock, Ringside's C.6 canonical tool-call translator normalizes the wire format.
JSON schema (response_format)
pythonresp = client.chat.completions.create( model="fc:anthropic/claude-haiku-4-5", # non-native json_schema provider messages=[{"role": "user", "content": "Generate a user record"}], response_format={ "type": "json_schema", "json_schema": { "name": "user", "schema": { "type": "object", "properties": {"name": {"type": "string"}, "age": {"type": "integer"}}, "required": ["name", "age"], }, }, }, user="cus_42", )
Ringside's enforcer (C.6) validates the response against your schema server-side. Up to 2 auto-retries with a reinforcement prompt on mismatch. Persistent failure returns 422 response_schema_validation_failed.
Using Customer attribution (the whole point)
Attribution via body field (default, OpenAI-compat)
pythonclient.chat.completions.create(model="...", messages=[...], user="cus_42")
Attribution via header (multi-tag)
pythonclient.chat.completions.create( model="fc:openai/gpt-4o-mini", messages=[...], user="cus_42", extra_headers={ "FC-Tag": "chat-support", "FC-Property-Plan": "enterprise", "FC-Session-Id": "workflow_abc", "X-FC-Billable-Amount": "0.25", # optional: what you're charging your customer for this call }, )
Then query per-Customer spend:
bashcurl -H "Authorization: Bearer ko_..." \ "https://api.fightclub.pro/v1/customers/cus_42/usage?from=2026-08-01"
Or margin (your charge vs. Ringside's cost):
bashcurl -H "Authorization: Bearer ko_..." \ "https://api.fightclub.pro/v1/customers/cus_42/margin?group_by=day"
Feature mapping
| OpenAI Chat Completions | Ringside equivalent |
|---|---|
api.openai.com/v1/chat/completions | api.fightclub.pro/v1/chat/completions |
api.openai.com/v1/embeddings | api.fightclub.pro/v1/embeddings |
api.openai.com/v1/moderations | api.fightclub.pro/v1/moderations (free at-cost on Pro+) |
model: "gpt-4o-mini" | model: "fc:openai/gpt-4o-mini" |
user: "<id>" (logging only) | user: "<id>" auto-creates tracked Customer + attribution |
| n/a | FC-Property-*, FC-Tag, FC-Session-Id, X-FC-Billable-Amount headers |
| n/a | GET /v1/customers/:id/usage + /margin |
| n/a | POST /v1/webhooks (13 event types) |
| n/a | POST /v1/customers/:id/client_tokens (frontend-safe JWTs) |
| n/a | Budget caps: PATCH /v1/customers/:id {monthly_budget_usd: N} |
| Streaming SSE | Identical chunk shape (byte-exact across providers) |
| Idempotency-Key header | Supported, 24-hour per-dev dedup window |
Gotchas
usermust be a stable opaque ID, not PII. Use an internal customer UUID or tenant ID. Don't pass emails. Ringside storesuserasexternal_idon the Customer row; you do not want PII there. UseFC-Property-Email: <email>if you want email-level tags.- Model prefix is required.
model: "gpt-4o"returns400 invalid_request_error. Always usefc:openai/gpt-4o(or any otherfc:<provider>/<model>, or aslot:<alias>). Bare model names are reserved for a possible OpenAI-only passthrough mode in v2. - Error envelope shape. Ringside wraps all errors as
{error: {code, message, type, param}}, compatible with the OpenAI SDK's error parser. Upstream provider errors are normalized to Ringside codes (upstream_unavailable,upstream_quota_exceeded,upstream_auth_failed,upstream_invalid_request,upstream_context_length_exceeded,upstream_content_filter) so you can write one error handler. - Rate limits. Per-dev, per-Customer (RPM/TPM you configure), and per-Client-Token RPM. 429s include a
Retry-Afterheader. - Moderations pricing. On the Developer tier, moderations pass through at cost + 10%. On Pro+, moderations run through Ringside's platform OpenAI key at cost with no markup, effectively free.
- Request IDs. Every response carries an
X-Request-Idheader. Log it. When you file a support ticket, include the request ID and we'll find the trace instantly.
FAQ
Q: What about latency? A: Ringside adds roughly 10–30ms of edge routing + attribution overhead on top of the upstream provider. Streaming first-byte latency is unaffected (we proxy the upstream SSE directly).
Q: GDPR / CCPA hard-delete? A: DELETE /v1/customers/:id?hard=true purges the Customer row + anonymizes all associated UsageEvents (user_external_id nulled, metadata scrubbed). Returns 204.
Q: Failover if OpenAI is down? A: Use slot:<alias> refs. One admin-side PATCH /admin/ringside/slots/chat-cheap can re-point slot:chat-cheap from fc:openai/gpt-4o-mini to fc:anthropic/claude-haiku-4-5 with zero app redeploys.
Q: SLA? A: Pro tier: 99.9% monthly uptime. Enterprise: 99.95% + runbook access. See /legal/sla.
Q: How do I migrate existing data? A: Chat Completions is stateless, so there is nothing to migrate. Your first call with user="cus_42" creates the Customer; subsequent calls attach to it. If you want to pre-create Customers (e.g. to set a budget), use POST /v1/customers.
Next steps
- Try it in the no-signup playground. Paste your existing request body, hit run.
- Full API reference:
ringside.fightclub.pro/docs. - Compatibility matrix (per provider × feature):
ringside.fightclub.pro/docs/compatibility. - Support:
support@fightclub.pro(4-business-hour response) or Discord#migration.
Related migrations
- OpenAI Assistants → Ringside
- Anthropic Messages → Ringside
- OpenRouter → Ringside
- Chatbase → Ringside
- Index
Corrections, feedback: chka@stratus5.com.