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.

  1. Open the dashboard

    On a fresh install no account exists yet, so every page sends you to /setup.

  2. 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.

  3. Name your first workspace

    /onboarding asks for a workspace name, then takes you to /apps to 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.

Create the admin right after you deploy. Until the admin exists, anyone who can reach the dashboard's URL can open /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.

RouteNav itemWhat you do there
/OverviewA setup checklist for new apps, then key numbers, usage over the last 30 days, accounts by plan, recent activity and top accounts.
/analyticsAnalyticsUsage over time per entitlement, top accounts and saved reports.
/agentAgentChat with an AI agent about your catalog and approve the changes it proposes. See Agent and MCP.
/offersOffersBuild offers, publish them and share their checkout links. See Offers.
/cancel-flowCancel flowEdit the questions and save offers your cancel button shows. See Cancel flows.
/plansCatalog → PlansPlans with their limits, add-ons, pricing card and metadata. See Catalog.
/entitlementsCatalog → EntitlementsThe features and limits you gate, as usage limits or feature flags.
/addonsCatalog → Add-onsOptional extras that plans and incentives include.
/incentivesCatalog → IncentivesOverrides you apply to single accounts: higher limits, extra features, add-ons.
/accountsCustomers → AccountsYour customers. Search, filter by plan or incentive, change an account's plan and see its live access and usage.
/developersDevelopers → IntegrationCopy-paste snippets with this app's real keys and IDs.
/developers/apiDevelopers → API referenceEvery endpoint, with a Try it panel that sends real requests.
/developers/mcpDevelopers → MCP serverConnect AI assistants and coding agents to the app, choose what they can do, and see every call. See MCP server.
/developers/keysDevelopers → API keysThe secret and public keys, and regenerating them. See Keys and webhooks.
/developers/webhooksDevelopers → WebhooksWebhook endpoints, delivery logs, the event log and Zapier.
/settingsApp settingsName 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.

  1. Start the API and the dashboard

    From the repo root, pnpm dev:api starts Postgres and the API in Docker, and pnpm dev:app starts the dashboard on http://localhost:6768.

  2. Open it

    Click Explore the demo workspace on the sign-in page. The button shows when DEMO_ENABLED=true is set on the dashboard. It defaults to on under next dev. The first click builds the demo workspace, which takes a few seconds. It's built again whenever the workspace has no apps left.

  3. 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 --reset

    The script calls the dashboard, so it needs the dashboard's URL (APP_URL, default http://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 --reset needs the API's ADMIN_API_KEY. Locally it defaults to dev-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/admin gateway 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/auth refuses 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 GET requests.

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-app/.env.local
OFFER_API_URL=mock

The 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.