BrandApp Playground

BrandApp Playground

Interactive demos and copy-paste code for @reopt-ai/brandapp-sdk. Every module in the sidebar has a live workspace on the left and the exact code you'd ship on the right.

Connection: EnvironmentCredentials from .env — the standard remote setupChange →

Not signed in yet.

Sign in with Reopt to exercise user-scoped endpoints (`sdk.auth.getUserInfo`, `linkCurrentUser`, `withdrawCurrentUser`). App-scoped demos below work without a session.

How the SDK talks to Reopt

Three credential flavours share a single SDK instance. Mix freely inside one request — e.g., fetch app-wide records with Basic Auth, then run a user-scoped userinfo lookup with the OAuth token you received from Better Auth.

Basic Auth

Client Credentials

`clientId:clientSecret` from your `.env`. Used by every app-scoped module (`eav`, `ai`, `cms`, `files`). No end user required — returns data across the brandapp.

Bearer

User access token

OAuth access token you get from Better Auth after the user signs in. Used by `sdk.auth.*` — scoped to that specific signed-in user. Required for Customer Visibility / Withdraw.

Dev Mode

In-memory server

`REOPT_DEV_MODE=true` spins up a local mock at :4300. Lets you build offline. Same SDK surface; state resets on restart. Use via `pnpm dev`.

Getting started

Four steps from a cold clone to exercising every SDK surface.

  1. 1

    Verify the connection

    /connection →

    Check which credentials the playground is using. Swap them per-dev via the cookie form — useful when you want to point at a staging brandapp without editing .env.

  2. 2

    Smoke-test the SDK

    /health →

    Run the full probe suite against the currently-wired backend. Non-destructive — reads entities, lists files, pings AI models, verifies webhook signatures, never mutates.

  3. 3

    Sign in with Reopt

    /auth →

    Unlocks user-scoped demos. Once signed in, /health auto-populates the Customer Visibility panel (session → access token → OIDC userinfo → linked BrandappCustomer).

  4. 4

    Open any module

    /eav →

    Each page pairs a live demo (left) with the exact code you'd ship (right), split across tabs for Server Setup / Client Setup / …

SDK module map

The SDK ships as multiple sub-path exports so bundlers can tree-shake what you don't use. The root export re-exports everything that's safe for both server + client.

Sub-pathPurpose
@reopt-ai/brandapp-sdkcreateReoptSDK, error classes, runtime types
/authUser-scoped Bearer calls (getUserInfo, link / withdraw)
/eavEntities, records, filter DSL (`where()`)
/eav/schema`defineSchema()` / `defineEntity()` type-safe schemas
/ai, /ai-providerLight AI client + Vercel AI SDK provider
/cmsPosts and post groups
/filesFolders, file mutations, content preview, and usage
/better-authBetter Auth database adapter + OAuth plugin
/webhooksSigned webhook handler and verifier
/logoutOIDC Single Logout — back-channel receiver + end-session URL
/react/hooksTanStack Query hooks
/dev, /testingIn-memory dev server and test fixtures

Live demos

Every card below is a dedicated page with a working demo and its source code side-by-side.

Quick start

Two snippets to get you from zero to end-to-end. Pair them with the Quick Start guide.

lib/sdk.ts
// 1. Create the SDK once — shared across the app
import { createReoptSDK } from "@reopt-ai/brandapp-sdk";

export const sdk = createReoptSDK({
  clientId: process.env.BRANDAPP_CLIENT_ID!,
  clientSecret: process.env.BRANDAPP_CLIENT_SECRET!,
  brandappId: process.env.BRANDAPP_ID!,
});

// 2. App-scoped calls use Basic Auth automatically
const entities = await sdk.eav.entities.list();
const credits = await sdk.ai.credits(); // CreditInfo — { balance, status, ... }
const { data: files } = await sdk.files.list({ limit: 20 });
app/api/me/route.ts
// 3. User-scoped calls take an OAuth access token you already hold
//    (retrieved via Better Auth's `auth.api.getAccessToken`).
const userInfo = await sdk.auth.getUserInfo(accessToken);

// 4. Link the signed-in user to a Brandapp customer (idempotent upsert).
const { customerId } = await sdk.auth.linkCurrentUser(accessToken);

// 5. Soft-withdraw (status → churned, junction removed, Stripe cancelled).
//    Customer record is retained so re-linking restores the same customerId.
await sdk.auth.withdrawCurrentUser(accessToken);