Cearsi logo
Cearsi AI

Build Cearsi into your product

The Cearsi platform ships as a REST API, a drop-in web widget, an MCP endpoint, and outbound webhooks — so you can embed the same financial education assistant your team uses inside your own app, portal, or agent.

Available on the Max and Business plans. Create keys in Settings → API Keys.

Quickstart

  1. Upgrade to Max on the billing page.
  2. Create an API key in Settings. Copy it — it's only shown once.
  3. Call POST https://cearsi.dev/api/public/v1/chat with a Bearer token.

REST API

Base URL: https://cearsi.dev/api/public/v1

POST /chat

Send a message and receive a response from Cearsi.

Editable snippet · TypeScriptPowered by Monaco (open source)

Edit locally, then paste into your project. Requests run from your own environment — Cearsi never executes this code.

cURL
curl https://cearsi.dev/api/public/v1/chat \
  -H "Authorization: Bearer csk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"message":"Explain how staking rewards are taxed in the US"}'
JavaScript / TypeScript
const res = await fetch("https://cearsi.dev/api/public/v1/chat", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CEARSI_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    message: "Explain how staking rewards are taxed in the US",
  }),
});
const { message } = await res.json();
console.log(message.content);
Python
import os, requests
r = requests.post(
  "https://cearsi.dev/api/public/v1/chat",
  headers={"Authorization": f"Bearer {os.environ['CEARSI_API_KEY']}"},
  json={"message": "Summarize MiCA in one paragraph"},
)
print(r.json()["message"]["content"])
Response
{
  "id": "chatcmpl_...",
  "object": "chat.completion",
  "message": { "role": "assistant", "content": "..." },
  "usage": { "prompt_tokens": 128, "completion_tokens": 220 }
}

Passing a full conversation

messages array
{
  "messages": [
    { "role": "user", "content": "What is a Roth IRA?" },
    { "role": "assistant", "content": "A Roth IRA is ..." },
    { "role": "user", "content": "What's the 2026 contribution limit?" }
  ]
}

JavaScript SDK

One-file ES module hosted on the Cearsi CDN — no npm install, no build step.

ES module (browser or Deno)
import { Cearsi } from "https://cearsi.dev/sdk/v1/cearsi.js";

const c = new Cearsi({ apiKey: "csk_live_..." });
const { message } = await c.chat("Explain how staking rewards are taxed in the US");
console.log(message.content);

Source: /sdk/v1/cearsi.js

Mobile SDK (React Native / Expo)

Same REST API, plus local conversation state, device persistence and a subscribe() hook so a chat screen re-renders automatically. Drop the file into your app (or vendor it from the CDN) and pass an AsyncStorage-compatible store.

1. Install the client
# copy the SDK into your app
curl -o src/lib/cearsi-mobile.js https://cearsi.dev/sdk/v1/cearsi-mobile.js
npx expo install @react-native-async-storage/async-storage
2. Create the client
// src/lib/cearsi.js
import AsyncStorage from "@react-native-async-storage/async-storage";
import { CearsiMobile } from "./cearsi-mobile";

export const cearsi = new CearsiMobile({
  apiKey: process.env.EXPO_PUBLIC_CEARSI_KEY, // csk_live_...
  storage: AsyncStorage,
  maxTurns: 20,
});
3. Chat screen
import { useEffect, useState } from "react";
import { View, Text, TextInput, FlatList, Pressable } from "react-native";
import { cearsi } from "../lib/cearsi";

export default function ChatScreen() {
  const [messages, setMessages] = useState([]);
  const [text, setText] = useState("");
  const [busy, setBusy] = useState(false);

  useEffect(() => {
    const off = cearsi.subscribe(setMessages);
    cearsi.load();
    return off;
  }, []);

  async function send() {
    const q = text.trim();
    if (!q || busy) return;
    setText(""); setBusy(true);
    try { await cearsi.send(q); }
    catch (e) { console.warn(e.message); }
    finally { setBusy(false); }
  }

  return (
    <View style={{ flex: 1, padding: 16 }}>
      <FlatList
        data={messages}
        keyExtractor={(_, i) => String(i)}
        renderItem={({ item }) => (
          <Text style={{ marginVertical: 6, textAlign: item.role === "user" ? "right" : "left" }}>
            {item.content}
          </Text>
        )}
      />
      <View style={{ flexDirection: "row", gap: 8 }}>
        <TextInput
          value={text}
          onChangeText={setText}
          onSubmitEditing={send}
          placeholder="Ask Cearsi about crypto, taxes, or finance…"
          style={{ flex: 1, borderWidth: 1, borderRadius: 10, padding: 10 }}
        />
        <Pressable onPress={send} disabled={busy}>
          <Text style={{ padding: 12 }}>{busy ? "…" : "Send"}</Text>
        </Pressable>
      </View>
    </View>
  );
}

Source: /sdk/v1/cearsi-mobile.js — ship the key from your own backend for production apps; a bundled key is visible to anyone who unpacks the binary. Restrict it by scope (chat:write) and rotate it from API keys settings.

Embeddable widget

Drop the Cearsi chat bubble onto any site. Create a key in API keys settings, add your domain(s) to Allowed origins, then paste the snippet below into your HTML.

One-line install
<script
  src="https://cearsi.dev/embed/v1/widget.js"
  data-key="csk_live_..."
  data-title="Ask Cearsi"
  data-color="#6d28d9"
  defer
></script>

The widget is scoped by Allowed origins on the key — Cearsi rejects any browser request whose Origin is not on your allowlist, so a leaked key from your marketing site cannot be reused elsewhere. Configure the allowlist in Settings → API Keys.

MCP endpoint

Cearsi exposes a Model Context Protocol server so Claude, Cursor, ChatGPT, and any custom agent can call its tools directly.

MCP URL
https://cearsi.dev/mcp

Uses OAuth 2.1 with dynamic client registration — no manual client setup required.

Outbound webhooks

Register an HTTPS endpoint in Settings → API Keys and receive chat.completed events. Each request carries an x-cearsi-signature: t=<timestamp>,v1=<hex> header.

Verifying a webhook (Node)
import { createHmac, timingSafeEqual } from "crypto";

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
  const expected = createHmac("sha256", secret)
    .update(parts.t + "." + rawBody).digest("hex");
  const a = Buffer.from(parts.v1); const b = Buffer.from(expected);
  if (a.length !== b.length || !timingSafeEqual(a, b)) throw new Error("bad sig");
  if (Math.abs(Date.now()/1000 - Number(parts.t)) > 300) throw new Error("stale");
}
Sample chat.completed payload
{
  "id": "evt_...",
  "event": "chat.completed",
  "created_at": "2026-07-18T12:00:00.000Z",
  "data": {
    "message": { "role": "assistant", "content": "..." },
    "input_messages": [ { "role": "user", "content": "..." } ],
    "usage": { "prompt_tokens": 128, "completion_tokens": 220 }
  }
}

Rate limits & fair use

  • Max plan: generous per-key request budget suitable for agent loops.
  • Domain allowlisting supported per key — set Allowed Origins in Settings → API Keys.
  • Revoke a key instantly from the settings page — takes effect on the next request.