Back to cookbook

Migrate from OpenAI in 3 lines

What you'll build

No new app, this is the smallest possible migration. You point your existing OpenAI-SDK code at https://api.fightclub.pro/v1, add an FC-Customer header on each request, and inherit everything Ringside gives you: per-customer billing, budgets, webhooks, retries, margin reports. Below shows the 3-line diff for Python; JS and Go are the same idea.

What you need

  • An FC API key (from /app/api-keys)
  • Your existing OpenAI-SDK code (Python, Node, or any of the 50+ compatible SDKs)

Full code

python
# before.py from openai import OpenAI client = OpenAI(api_key=os.environ["OPENAI_API_KEY"]) def chat(msg: str) -> str: r = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": msg}], ) return r.choices[0].message.content
python
# after.py — 3 lines changed. from openai import OpenAI client = OpenAI( api_key=os.environ["FC_API_KEY"], # 1. new key base_url="https://api.fightclub.pro/v1", # 2. base URL ) def chat(msg: str, customer: str) -> str: r = client.chat.completions.create( model="fc:openai/gpt-4o-mini", # required: prefix with fc: messages=[{"role": "user", "content": msg}], extra_headers={"FC-Customer": customer}, # 3. attribute the request ) return r.choices[0].message.content

JavaScript:

js
// after.js import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.FC_API_KEY, baseURL: 'https://api.fightclub.pro/v1', }); const r = await client.chat.completions.create({ model: 'fc:openai/gpt-4o-mini', messages: [{ role: 'user', content: 'hi' }], }, { headers: { 'FC-Customer': 'cus_alice' }, });

Environment-variable style (base URL + key move out of code):

bash
export OPENAI_BASE_URL=https://api.fightclub.pro/v1 export OPENAI_API_KEY=sk_live_xxx_from_ringside

The base URL and key drop into env vars, but every model string still needs an fc: prefix (e.g. fc:openai/gpt-4o-mini) — a bare gpt-4o returns 400 invalid_model_ref.

Walkthrough

What stays identical: chat.completions.create signatures, embeddings.create, the Assistants API surface, streaming semantics, response_format, tool calling, max_tokens — the request and response shapes are wire-compat. The one thing you change in code is the model string: add an fc: prefix.

What's new: you get three Ringside-specific error codes you didn't have before. invalid_api_key (401) means your FC key is wrong or revoked. rate_limited (429) respects both per-dev limits and per-Customer RPM/TPM, check the Retry-After header. budget_exceeded (402) fires once a Customer has spent past its cap; the fix is PATCH /v1/customers/:id to raise budget_usd. All three map cleanly to the SDK's exception classes.

What to do with the fc: prefix: required. Every model ref must start with fc: (a direct model, e.g. fc:openai/gpt-4o-mini), slot: (a dev-configured alias so you can swap the underlying model without redeploying), or match: (a declarative selector). A bare gpt-4o-mini returns 400 invalid_model_ref.

Per-customer attribution is where the value lives. Without FC-Customer, usage aggregates against your dev account. With it, you get /v1/usage?group_by=customer, per-customer budgets, per-customer rate limits, and /v1/margin (revenue vs cost per customer). Almost every recipe in this cookbook hinges on this one header.

Run it

bash
export FC_API_KEY=sk_live_xxx python after.py

What's next