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.
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.
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.
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.
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
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
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
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
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-path | Purpose |
|---|---|
| @reopt-ai/brandapp-sdk | createReoptSDK, error classes, runtime types |
| /auth | User-scoped Bearer calls (getUserInfo, link / withdraw) |
| /eav | Entities, records, filter DSL (`where()`) |
| /eav/schema | `defineSchema()` / `defineEntity()` type-safe schemas |
| /ai, /ai-provider | Light AI client + Vercel AI SDK provider |
| /cms | Posts and post groups |
| /files | Folders, file mutations, content preview, and usage |
| /better-auth | Better Auth database adapter + OAuth plugin |
| /webhooks | Signed webhook handler and verifier |
| /logout | OIDC Single Logout — back-channel receiver + end-session URL |
| /react/hooks | TanStack Query hooks |
| /dev, /testing | In-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.
Data
App-scoped resources the SDK manages with Basic Auth. Queries run with the brandapp's Client Credentials.
AI
Text + image generation, billed against the brandapp's AI credit pool.
Auth & Customer
User-scoped endpoints (Bearer). Sign in with Reopt to exercise these.
Integration
React, webhooks, and the local developer loop.
React Hooks
TanStack Query hooks for EAV, AI, CMS, and Files
Webhooks
`createWebhookHandler()` with signature + replay verification
Dev Server
In-memory Reopt API via `createDevServer()` for offline work
Testing Utils
`createTestSDK()` and fixtures for Vitest / Playwright
Error Handling
Error classes, `instanceof` checks, `.diagnostic` payloads
Quick start
Two snippets to get you from zero to end-to-end. Pair them with the Quick Start guide.
// 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 });// 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);