Ringside · Migration guide

Persona · Solo-Dev Sam → Team Lead Tanya

Updated 2026-04-20

Migrating from Chatbase to Ringside

Chatbase ships UI + agent. Ringside ships primitives. When your no-code chatbot outgrows Chatbase's framework (provider choice, SDK-level prompt control, your own UI, per-end-customer billing, or integrations Chatbase doesn't support), Ringside is the next step. This guide walks you through migrating without losing what you already had working.

Status: v1 (2026-04-20).

See also: Migration library index.


Should you migrate?

Chatbase is excellent at what it does: a no-code SaaS that gives you a trainable chatbot, a chat widget, and a dashboard, in an afternoon. If that's enough, stay on Chatbase.

Migrate to Ringside when any of these apply:

  1. You need per-customer billing. Chatbase bills you for total message volume. You can't cleanly pass that cost through to your end-customers.
  2. You need provider choice. Chatbase is OpenAI-first; Ringside gives you 19 providers behind one SDK, and you can swap models per-request or via slot:<alias>.
  3. You need SDK-level control. Custom tools, structured output via JSON schemas, streaming to your own UI, retrieval pipelines you own. All of this is API-shaped, not widget-shaped.
  4. You need your own UI. Chatbase's widget is fine for simple FAQ bots; if you want a brand-native chat experience, you have to own the front-end anyway.
  5. You need webhooks on operational events. customer.budget_exceeded, wallet.low, run.failed, moderation.flagged. Ringside ships 13 event types, HMAC-signed, retried.

If those boxes are unchecked, Chatbase is still the right call. Bookmark this guide for later.


What you keep. What you lose. What you gain.

You keep

  • Your training documents. Export from Chatbase, re-index with any RAG stack (Supabase, Pinecone, etc.) + Ringside's /v1/embeddings.
  • Your conversation history. Ringside's /v1/customers/:id/conversations replaces Chatbase's thread storage 1:1.
  • Your chatbot persona / system prompt. Goes straight into a Ringside Assistant via POST /v1/assistants {instructions: "..."}.

You lose

  • The widget. You have to build or buy your own chat UI. Good news: shadcn/ui, Vercel's ai package, or 20+ OSS React components all do this in a day.
  • Chatbase's analytics dashboard. Replaced by Ringside's /ringside/app/customers/[id]/usage + the request log at /ringside/app/logs.
  • Built-in lead capture form. Trivial to re-implement in your UI: post to your own backend, then call POST /v1/customers to create the Ringside Customer.

You gain

  • 19 LLM providers, one SDK. Swap Claude, Llama 3, Gemini, Mistral on the same client code.
  • Per-end-customer billing + budgets. Bill each of your customers independently; hard-cap their monthly spend.
  • Webhooks on 13 operational events.
  • Client Tokens. Short-lived JWTs your browser can use directly (after your backend mints them), scoped to a single Customer with optional Origin allowlist.
  • Margin reporting. Track what you charge vs. what Ringside costs you, per Customer, per model, per day.
  • Assistants API wire-compat. If you ever want OpenAI-SDK Assistants behaviour, that's built-in.
  • GDPR hard-delete. DELETE /v1/customers/:id?hard=true.

Step-by-step migration

Step 1: Sign up + create a server token (5 minutes)

ringside.fightclub.pro/register?intent=ringside → $10 credit, no card. Create a server token at /ringside/app/api-keys/new.

Step 2: Export your Chatbase chatbot config

In the Chatbase dashboard, export the chatbot's instructions + the training documents. We'll call these instructions.txt and docs/*.md.

Step 3: Map each Chatbase "chatbot" to a Ringside Assistant

python
from openai import OpenAI client = OpenAI(api_key="ko_...", base_url="https://api.fightclub.pro/v1") assistant = client.beta.assistants.create( name="Support Bot", instructions=open("instructions.txt").read(), model="fc:openai/gpt-4o-mini", # or fc:anthropic/claude-haiku-4-5, etc. tools=[{ "type": "function", "function": { "name": "search_docs", "description": "Retrieve relevant training docs for a query", "parameters": { "type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"], }, }, }], ) print(assistant.id) # asst_...

Step 4: Index your training documents

Chatbase's built-in RAG is replaced with your own. Simplest stack: Supabase + pgvector + Ringside's /v1/embeddings:

python
emb = client.embeddings.create( model="fc:openai/text-embedding-3-small", input=[doc.read() for doc in training_docs], ) # Store emb.data[i].embedding alongside the doc chunks in Supabase / Pinecone / etc.

Your search_docs function-tool becomes: compute query embedding → top-k vector search → return matched passages.

Step 5: Map each Chatbase end-user to a Ringside Customer

Ringside auto-creates Customers on first user=<id> pass, but if you want to pre-populate budgets + metadata:

python
for cbase_user in chatbase_users_export: client.post( # POST /v1/customers (raw HTTP here; no SDK method yet) "/customers", json={ "external_id": cbase_user["id"], "name": cbase_user["name"], "monthly_budget_usd": 10, # hard cap per Customer "metadata": {"source": "chatbase_migration"}, }, )

Step 6: Build your own chat UI

Minimal React snippet using Client Tokens for browser-safe calls + SSE streaming:

jsx
// Backend mints a Client Token for this Customer (keep server token server-side!) // POST /v1/customers/cus_42/client_tokens → { token: "eyJ...", expires_at: ... } // Frontend (React) — uses the Client Token directly: import { useState } from "react"; export function Chat({ clientToken, conversationId }) { const [messages, setMessages] = useState([]); async function send(text) { const resp = await fetch( `https://api.fightclub.pro/v1/customers/cus_42/conversations/${conversationId}/messages`, { method: "POST", headers: { Authorization: `Client ${clientToken}`, "Content-Type": "application/json", }, body: JSON.stringify({ role: "user", content: text, stream: true, }), } ); const reader = resp.body.getReader(); const decoder = new TextDecoder(); let assistant = ""; while (true) { const { value, done } = await reader.read(); if (done) break; // Parse OpenAI-shape SSE chunks const chunk = decoder.decode(value); for (const line of chunk.split("\n")) { if (!line.startsWith("data: ")) continue; const payload = line.slice(6).trim(); if (payload === "[DONE]") return; const delta = JSON.parse(payload).choices?.[0]?.delta?.content ?? ""; assistant += delta; setMessages((m) => [...m.slice(0, -1), { role: "assistant", content: assistant }]); } } } return ( <div> {messages.map((m, i) => <p key={i}>{m.role}: {m.content}</p>)} <input onKeyDown={(e) => e.key === "Enter" && send(e.currentTarget.value)} /> </div> ); }

Your backend mints a new Client Token every 15 minutes (default TTL) and serves it to the authenticated user. That's ~20 lines of server code.

Step 7: Migrate conversations (optional)

If you want to preserve chat history: export Chatbase conversations → create Ringside Conversations → replay messages:

python
for cbase_conv in chatbase_conversations_export: conv = client.post( f"/customers/{cbase_conv['user_id']}/conversations", json={"metadata": {"source_chatbase_id": cbase_conv["id"]}}, ) for msg in cbase_conv["messages"]: client.post( f"/customers/{cbase_conv['user_id']}/conversations/{conv['id']}/messages", json={"role": msg["role"], "content": msg["content"], "skip_llm": True}, )

(skip_llm: true appends the message without triggering a new LLM run, useful for replay. Available on v1.1+.)


Feature mapping

ChatbaseRingside equivalent
"Chatbot" (template + training docs + model)POST /v1/assistants + your own RAG stack (Supabase/Pinecone + /v1/embeddings)
Training documentsEmbed via /v1/embeddings, store in your vector DB
End-users ("chat users")POST /v1/customers (or auto-create via user: "<id>")
Conversations (thread history)POST /v1/customers/:id/conversations + /messages
Chat widgetBuild your own (shadcn/ui, custom React, whatever)
Lead capture formsYour own form; call POST /v1/customers on submit
Usage dashboard/ringside/app/customers/[id] + /ringside/app/usage
Webhook on new messagePOST /v1/webhooks {events: ["run.completed", ...]}
Per-chatbot model selectionmodel: "fc:<provider>/<model>" or slot:<alias> on each call
Message rate limitsPer-Customer RPM/TPM (PATCH /v1/customers/:id {rpm: 60, tpm: 10000})
n/aPer-Customer monthly budget caps (monthly_budget_usd)
n/aMargin reporting (/v1/customers/:id/margin)
n/a19 provider choices
n/aClient Tokens (browser-safe Ed25519 JWTs)
n/aGDPR hard-delete

Gotchas

  • UI is all you. Chatbase's theming panel, widget embed, analytics overlay: none of it exists in Ringside. Budget 1-3 days to build or buy a chat UI (shadcn/ui + ai package is fastest).
  • Your backend must mint Client Tokens. Never ship your ko_... server token to the browser. Your server mints short-lived Client Tokens (POST /v1/customers/:id/client_tokens), browser uses them to call chat/completions + conversations/*/messages directly. Auto-refresh before expiry.
  • No built-in RAG. You own the vector store. Supabase + pgvector is 50 lines of setup. Pinecone is one pip install. Ringside's /v1/embeddings gives you the vectors.
  • Lazy Customer auto-creation. Passing user: "cus_xyz" on a first call creates the Customer with no budget, no metadata. If you care about budgets, pre-create via POST /v1/customers.
  • Conversation lock. Only one LLM call can run against a conversation at a time. If your UI fires a second message while the first is still streaming, you'll get 409 conversation_locked. Debounce, or create a second conversation.
  • 5,000-message cap per conversation. After 5k messages, POST /messages returns 409 conversation_full. Long-running FAQ bots should rotate conversations (one per session, or one per calendar week).

FAQ

Q: What if I want Chatbase-like simplicity but more flexibility? A: Ringside's Assistants API (/v1/assistants, /v1/threads, /v1/threads/:id/runs) is a closer 1:1 mental model to Chatbase's "chatbot" concept: a named agent with instructions that maintains thread state. See openai-assistants-to-ringside.md for the full OpenAI-SDK pattern (works the same way here).

Q: Does Ringside do content moderation like Chatbase? A: Yes. POST /v1/moderations (OpenAI-compat, free at-cost on Pro+). Call it on inbound user messages before passing to the LLM. moderation.flagged webhook fires on flagged content.

Q: Do I need a separate billing system to charge my end-customers? A: Stripe + Ringside is the standard combo. Ringside tells you what each Customer cost you; Stripe charges your Customer. Use GET /v1/customers/:id/usage nightly to sync usage → Stripe meters (or your own invoicing).

Q: How much does this cost vs. Chatbase? A: Chatbase's Pro plan is $40/mo for 2,000 messages on GPT-4o-mini = ~$0.02/message. Ringside is $99/mo base (Pro) + ~$0.0003/message on gpt-4o-mini + 6% markup = ~$0.00032/message. For 10k+ messages/mo, Ringside is cheaper. For under 2k, Chatbase is simpler + cheaper.

Q: Support? A: support@fightclub.pro (4-business-hour response) or Discord #migration. White-glove migration (first 10 customers, free): book a 1-hour call.


Next steps

Related migrations


Corrections, feedback: chka@stratus5.com.