Dashboard tour
The dashboard (offer-app) is where your team edits the catalog, builds offers and cancel flows, reads usage and manages keys and webhooks. This page shows where each of those lives.
The dashboard is a Next.js app that talks to the Offer API through its own backend. Your browser calls /api/admin/* on the dashboard, which checks your session and forwards the request to the API with the admin key. It only forwards /apps/:appId/* when that app belongs to your active workspace.
First user: the admin
Each install has a single dashboard account, the admin. There's no open sign-up: the first person to open a fresh install creates the admin account, and after that the dashboard only offers sign-in. Accounts use email and password through better-auth.
Open the dashboard
On a fresh install no account exists yet, so every page sends you to
/setup.Create the admin account
Enter your name, email and a password of at least 8 characters, then click Create admin account. You're signed in straight away. There's no password reset email, so keep the password somewhere safe.
Name your first workspace
/onboardingasks for a workspace name, then takes you to/appsto create your first app.
From then on, /setup and the old /sign-up address redirect to /sign-in, and the API refuses any new sign-up with a 403, so another account can't be created by calling it directly either. The shared demo login (when DEMO_ENABLED is on) doesn't count as the admin, and opening the demo before setup doesn't close it.
/setup and become the admin. To check from a script, GET /api/auth/setup-status on the API (with the admin key) returns { "needs_setup": true } until then.Signing in
After setup, sign in at /sign-in with the admin's email and password. With the hosted API, better-auth runs inside the API on Postgres and the dashboard proxies /api/auth/* to it, so session cookies stay on the dashboard's domain. In mock mode it runs inside the dashboard process with an in-memory store.
Workspaces
A workspace holds your apps. Each install has a single workspace, named during onboarding and owned by the admin; the API refuses to create a second one. The admin is the workspace's only member, so there's no members page or invitations.
Workspace settings live under /settings: General (name, slug and ID) and Profile (your name, appearance, password and sessions).
Apps
An app is one product you sell. Each app has its own catalog, customer accounts, API keys, offers, cancel flow and webhooks. Create one from All apps (/apps) or the + tile in the rail. The Create app dialog asks for a name and what to start with:
- Blank app
- An empty catalog.
- SaaS sample
- Free, Starter, Pro, Enterprise and Lifetime deal plans with usage limits, add-ons and incentives, plus sample accounts and usage history. Against the hosted API it also creates a draft offer and an active cancel flow. Mock mode creates neither.
- Course sample
- Free preview, Core course and All access: one-time access tiers for an online course, with sample accounts and usage.
App settings (/apps/[appId]/settings) holds the app's name and ID, the Payments section for PayPal and your checkout page, and Delete app, which removes the app and everything in it after you type its name.
The layout
The dashboard has three columns.
- App rail
- The narrow column on the left. The logo opens the workspace menu (All apps, New app, Workspace settings). Below it is one tile per app, then a light/dark toggle, settings and your account menu (Profile, Workspace settings, Theme, Sign out).
- Nav panel
- The pages of the app you're in, or the workspace pages when you're on /apps or /settings. It starts with the Quick actions button.
- Page
- The page itself, with a header and toolbar at the top. Record pages have a details panel on the right.
On narrow screens the rail and nav panel fold into a drawer that you open from the page header.
App navigation
Items are listed in the order the nav panel shows them. Routes are relative to /apps/[appId], so / is the app's Overview.
| Route | Nav item | What you do there |
|---|---|---|
| / | Overview | A setup checklist for new apps, then key numbers, usage over the last 30 days, accounts by plan, recent activity and top accounts. |
| /analytics | Analytics | Usage over time per entitlement, top accounts and saved reports. |
| /agent | Agent | Chat with an AI agent about your catalog and approve the changes it proposes. See Agent and MCP. |
| /offers | Offers | Build offers, publish them and share their checkout links. See Offers. |
| /cancel-flow | Cancel flow | Edit the questions and save offers your cancel button shows. See Cancel flows. |
| /plans | Catalog → Plans | Plans with their limits, add-ons, pricing card and metadata. See Catalog. |
| /entitlements | Catalog → Entitlements | The features and limits you gate, as usage limits or feature flags. |
| /addons | Catalog → Add-ons | Optional extras that plans and incentives include. |
| /incentives | Catalog → Incentives | Overrides you apply to single accounts: higher limits, extra features, add-ons. |
| /accounts | Customers → Accounts | Your customers. Search, filter by plan or incentive, change an account's plan and see its live access and usage. |
| /developers | Developers → Integration | Copy-paste snippets with this app's real keys and IDs. |
| /developers/api | Developers → API reference | Every endpoint, with a Try it panel that sends real requests. |
| /developers/mcp | Developers → MCP server | Connect AI assistants and coding agents to the app, choose what they can do, and see every call. See MCP server. |
| /developers/keys | Developers → API keys | The secret and public keys, and regenerating them. See Keys and webhooks. |
| /developers/webhooks | Developers → Webhooks | Webhook endpoints, delivery logs, the event log and Zapier. |
| /settings | App settings | Name and ID, Payments (PayPal and your checkout page), and deleting the app. |
Offers and Cancel flow only appear when the API supports them, so they are hidden in mock mode. Agent is hidden on the demo login.
Analytics
Analytics charts the usage your app reports through the usage endpoints. The toolbar picks a period (7D, 30D, 60D, 6M, 1Y or All) and which entitlements to include. The page shows totals, Usage over time (by amount or by number of calls), By entitlement (select rows to focus the page on them) and Top accounts.
Save report stores the selected entitlements and period under a name. Reports are saved on the app, so everyone in the workspace sees them. The reports menu applies, updates, renames or deletes them. Each account page has its own Analytics tab with the same numbers for one account.
These views read GET /apps/:appId/analytics/timeseries, …/analytics/events and …/analytics/reports. If the API you point at doesn't have them, the dashboard hides those parts instead of failing.
Quick actions
Press ⌘K (Ctrl+K on Windows and Linux) or click Quick actions at the top of the nav panel. With no query it lists:
- Navigate: the current app's pages from the nav panel, except Cancel flow. Agent is left out on the demo login.
- Create: New plan, New entitlement, New add-on, New incentive, New offer and New account.
- Workspace: All apps, New app, Workspace settings, switching between light and dark, and Use system theme.
Navigate and Create only show inside an app. On /apps and /settings the list has the Workspace group alone.
Typing also searches the current app's plans, incentives and entitlements by name or ID, and its accounts by name or ID. Matching records are listed first.
The demo workspace
The demo workspace is a shared login with sample data, for showing the dashboard without setting anything up. It signs in as demo@offersdk.dev (password demo-password) to a workspace called Acme Labs with two apps: Notebook AI (a SaaS) and Course Hub (an online course). Both have catalogs, accounts that signed up over several months, usage history and saved reports. Against the hosted API, Notebook AI also has a draft offer and an active cancel flow.
Start the API and the dashboard
From the repo root,
pnpm dev:apistarts Postgres and the API in Docker, andpnpm dev:appstarts the dashboard onhttp://localhost:6768.Open it
Click Explore the demo workspace on the sign-in page. The button shows when
DEMO_ENABLED=trueis set on the dashboard. It defaults to on undernext dev. The first click builds the demo workspace, which takes a few seconds. It's built again whenever the workspace has no apps left.Reset it
# rebuild the demo apps from scratch pnpm seed:demo --reset # against a deployed dashboard, with the API's admin key APP_URL=https://your-dashboard.example.com ADMIN_API_KEY=… pnpm seed:demo --resetThe script calls the dashboard, so it needs the dashboard's URL (
APP_URL, defaulthttp://localhost:6768). With--reset, the dashboard deletes the demo apps and builds them again from the sample data. The demo login can't do that, so--resetneeds the API'sADMIN_API_KEY. Locally it defaults todev-admin-key. In mock mode the dashboard refuses--reset; restart the dev server instead. Without--reset, the script builds the demo ahead of the first click and leaves an existing one alone.
The demo is read-only
Many visitors share the demo login, so it can look at everything and change nothing. You can open every page, browse the catalogs, accounts and analytics, and preview offers and cancel flows, but nothing saves. A banner at the top of each page says so, and the workspace and profile settings are disabled.
- The dashboard's
/api/admingateway only lets the demo login read. The two exceptions are the previews that save nothing: an offer's checkout preview and a cancel flow's save offer preview. - The dashboard's
/api/authrefuses changes to the demo login's profile, email, password and sessions, and to its workspace and members. - The hosted API refuses the same account and workspace changes for the demo login. It also lets the demo apps' secret keys, which the dashboard shows, make only
GETrequests.
Refused calls answer 403 with “The demo workspace is read-only. Sign in with your admin account to make changes.” The dashboard checks these itself, so the demo is read-only in mock mode too.
The Agent is off for the demo login. It's left out of the nav and Quick actions, /apps/[appId]/agent redirects to the app's Overview, and POST /api/agent answers 403.
Mock mode
To run the dashboard without the API or a database, set this in offer-app/.env.local:
OFFER_API_URL=mockThe dashboard then serves an in-memory copy of the Offer API with the same routes, status codes and key permissions, and runs better-auth in-process. Everything resets when the dev server restarts.
- The demo account is created automatically with its two sample apps, and Explore the demo workspace always shows.
- The mock is also served at
/api/mock/*and accepts each app's real secret and public keys, so snippets, curl and the API reference's Try it work locally. The API keys page labels the connection Mock API (in-memory). - The mock doesn't sell anything or run cancel flows. The Offers and Cancel flow nav items and the Payments settings are hidden.
- The mock has no MCP server. Developers → MCP server is marked Preview and shows sample connections and activity. Its switches only change local state.
Under next dev with no OFFER_API_URL, the dashboard connects to the API at http://localhost:6767 with the development admin key. Builds and tests use the mock unless OFFER_API_URL is set. The full list of variables is in Environment variables.