The Docs.
Get up and running in 5 minutes. Drop in an OpenAI SDK base URL, attach a Customer header and you're live.
Quickstart
One curl. Drop-in SDK call. Then add the FC-Customer header to start attributing spend.
curl https://api.fightclub.pro/v1/chat/completions \
-H "Authorization: Bearer $FC_API_KEY" \
-H "FC-Customer: cus_42" \
-d '{"model":"fc:openai/gpt-4o-mini","messages":[{"role":"user","content":"Hello"}]}'Get your API key in the dashboard.
Authentication
Two auth modes. Pick based on where the call originates.
- API keys (server-side), long-lived
sk_live_*. Use anywhere you can keep a secret. - Client Tokens (browser), short-lived JWTs (15 min default, 1 h max) scoped to one Customer + Origin + IP. Mint on your server via
POST /v1/customers/:id/client_tokens, ship to the browser, browser calls Ringside directly withAuthorization: Client <jwt>.
Customers
Customers are first-class. Think of them as the Stripe-Customer-for-AI.
- Create one per end-user / tenant in your app
- Attach monthly budget cap + per-request rate limits (RPM / TPM)
- Pass the
FC-Customerheader on every call to attribute spend - Receive
budget.exceeded+wallet.lowwebhooks
Prepaid customer wallet
Customers can also carry a prepaid wallet balance, useful for credit-based products, chatbots, or any app where end-users pay in advance.
POST /v1/customers/:id/wallet/topup, add credits to a customerGET /v1/customers/:id/wallet, live balance + full transaction history- Each LLM call automatically debits
billable_amount_usdfrom the wallet and returnsX-Ringside-Wallet-Balance/X-Ringside-Wallet-Deductedresponse headers - Requests are blocked with
402 customer_wallet_emptywhen the balance reaches zero - Transaction types:
topup,debit,adjust,refund
Models
19+ providers in one namespace. Every model ref needs a prefix: fc:<provider>/<model> for a direct model (e.g. fc:openai/gpt-4o-mini), slot:<alias> for a dev-defined alias, or match:<selector> for a declarative pick. A bare name like gpt-4o returns 400 invalid_model_ref. Live pricing on the pricing page.
Streaming
Set stream: true to receive Server-Sent Events. Format matches OpenAI byte-for-byte. Cancel mid-stream by aborting the request. No reconnect/resume in v1.
Errors
Every error returns a JSON envelope:
{
"error": {
"type": "invalid_request_error",
"code": "budget_exceeded",
"message": "Customer cus_42 has exhausted its monthly budget.",
"request_id": "req_abc",
"retry_after_seconds": null
}
}Common codes: invalid_api_key (401), customer_budget_exceeded (402), customer_wallet_empty (402), wallet_empty (402), customer_rate_limit_exceeded (429), model_unavailable (503), invalid_request (400), conversation_locked (409).
Rate limits
Four layers, applied in order. The lowest limit hit wins.
- Edge / per-IP, drive-by abuse
- Per-Client-Token, browser tokens
- Per-developer (you), your account
- Per-Customer, your end-user's setting
Every response includes X-RateLimit-Remaining and on 429 a Retry-After header.
Webhooks (TL;DR)
Register a URL, receive HMAC-signed events. Verify the X-FC-Signature header.
Full guide → /docs/webhooks
SDKs
Two ways to call Ringside. Pick whichever fits your stack.
1. Use the OpenAI SDK (drop-in)
Wire-compatible. Swap the base URL and your existing OpenAI client keeps working — chat, embeddings, images, audio, files, batch, assistants.
from openai import OpenAI client = OpenAI(base_url="https://api.fightclub.pro/v1", api_key=os.environ["FC_API_KEY"])
2. Use the official Ringside SDK
Thin layer on top — adds typed helpers for the Ringside-only primitives: match: model selector (rolls forward across model versions automatically), per-end-customer CRUD against /v1/customers, webhook signature verification, Client Tokens. The OpenAI surface stays the same; you call client.chat.completions.create(...) exactly like before.
Available in four languages:
pip install ringside(Python)npm install @ringside/sdk(TypeScript / Node)go get github.com/fightclub/ringside-go(Go)pro.fightclub:ringside-sdk:0.1.0(Java 17+, Maven)
Same shape across every SDK — newest Sonnet at major version ≥ 4, resolved at request time:
from ringside import Ringside, Model
client = Ringside(api_key=os.environ["FC_API_KEY"])
model = Model.match("anthropic", "sonnet").min_version(4).build()
# -> "match:anthropic/sonnet>=4"
reply = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "Hello"}],
)
# Inspect what actually served (X-Ringside-Model-Resolved header):
# raw = client.chat.completions.with_raw_response.create(...)
# raw.http_response.headers["x-ringside-model-resolved"]
All four SDKs also ship client.customers (CRUD), client.webhooks.verify() (HMAC-SHA256 with replay protection), and the same Model.match() / Model.fc() builders. Source + examples: github.com/fightclub. Cookbook recipes at /examples.
Vector stores (managed RAG)
Vector stores ingest customer files, parse them into searchable chunks, embed and index them inside a per-customer tenant. Query via the OpenAI file_search tool inside any Assistants run.
# 1. Create a store
curl https://api.fightclub.pro/v1/vector_stores \
-H "Authorization: Bearer $FC_API_KEY" \
-d '{"name":"acme-handbook","embedding_model":"text-embedding-3-small"}'
# 2. Upload + attach a file
curl https://api.fightclub.pro/v1/files \
-H "Authorization: Bearer $FC_API_KEY" \
-F purpose=attachments -F file=@handbook.pdf
# => { "id": "file_xyz" }
curl https://api.fightclub.pro/v1/vector_stores/vs_abc/files \
-H "Authorization: Bearer $FC_API_KEY" \
-d '{"file_id":"file_xyz"}'
# 3. Query inside an Assistants run
curl https://api.fightclub.pro/v1/threads/$THREAD/runs \
-H "Authorization: Bearer $FC_API_KEY" \
-d '{
"assistant_id":"asst_...",
"tools":[{"type":"file_search","file_search":{"vector_store_ids":["vs_abc"]}}]
}'File ingest is asynchronous. vector_stores.files.create returns immediately with status='pending'. Poll the file status or subscribe to the vector_store.file.completed webhook.
Open MIME surface in v1: PDF, Word, slides, Markdown, HTML, plain text, code, JSON/YAML/XML, images with text (routed through a vision-capable model), audio (transcribed), CSV tables (parsed into row-narratives). You pay parse tokens for what the parser actually ran.
Embedding model is picked at store-create time, switchable later. The dashboard runs a background re-embed against cached parses and atomically swaps the index when done. The old index sticks around for 7 days for rollback. You pay embedding tokens only.
Per-customer isolation by default. Cross-customer reads return 404, not 403.
The browse/poll/manage surface is OpenAI-compatible. Common follow-ups:
# List stores
curl https://api.fightclub.pro/v1/vector_stores \
-H "Authorization: Bearer $FC_API_KEY"
# List + poll files in one
curl https://api.fightclub.pro/v1/vector_stores/vs_abc/files \
-H "Authorization: Bearer $FC_API_KEY"
curl https://api.fightclub.pro/v1/vector_stores/vs_abc/files/file_xyz \
-H "Authorization: Bearer $FC_API_KEY"
# Batch-attach up to 500 file_ids in one call
curl https://api.fightclub.pro/v1/vector_stores/vs_abc/file_batches \
-H "Authorization: Bearer $FC_API_KEY" \
-d '{"file_ids":["file_1","file_2","file_3"]}'
# Query log + aggregated stats (window=24h|7d|30d)
curl "https://api.fightclub.pro/v1/vector_stores/vs_abc/queries?limit=50" \
-H "Authorization: Bearer $FC_API_KEY"
curl "https://api.fightclub.pro/v1/vector_stores/vs_abc/stats?window=7d" \
-H "Authorization: Bearer $FC_API_KEY"
# Switch embedding model (background re-embed, atomic swap, 7-day rollback)
curl https://api.fightclub.pro/v1/vector_stores/vs_abc/migrate \
-H "Authorization: Bearer $FC_API_KEY" \
-d '{"embedding_model":"text-embedding-3-large"}'Full surface (PATCH, DELETE, file detach, cancel/retry on stuck ingests, batch retrieve/cancel, migrations list and rollback): /docs/vector_stores.
Deeper: /rag for the product page, /tutorials/managed-rag-quickstart for the 15-minute walkthrough, /examples/file-search-citations for the citation-parsing recipe.