Skip to content
Whop SaaS Starter
Guides

API Reference

All API endpoints with auth requirements and usage

All API routes are in app/api/. Every mutation endpoint verifies authentication — do not rely on the proxy alone.

Authentication

GET /api/auth/login

Initiates the Whop OAuth flow. Generates PKCE challenge, stores state in a cookie, and redirects to Whop.

ParamDescription
nextURL to redirect to after login (default: /dashboard)

GET /api/auth/callback

OAuth callback. Exchanges the authorization code for tokens, creates/updates the user, sets the session cookie, and redirects to the next URL.

  • First user to sign in becomes admin (isAdmin: true)
  • Sends welcome email to new users (if email provider configured)

GET /api/auth/logout

Clears the session cookie and redirects to /.

GET /api/auth/me

Returns the current user session (for client-side checks).

Auth: Required Response: { userId, email, name, plan, isAdmin, ... } or { error: "Not authenticated" } (401)

POST /api/auth/delete-account

Permanently deletes the authenticated user's account.

Auth: Required Body: { "confirmation": "DELETE" } Response: { success: true } or { error } (400/401)

Billing

GET /api/billing/portal

Redirects paid users to Whop's self-service billing portal. Free users are redirected to /pricing.

Auth: Required (via session cookie)

POST /api/billing/uncancel

Reverses a pending subscription cancellation via the Whop API.

Auth: Required Response: { success: true } or { error } (400/401/500)

Webhooks

POST /api/webhooks/whop

Receives webhook events from Whop. Verified via HMAC-SHA256 (standardwebhooks format).

Auth: Webhook signature verification (not session-based)

Handled events:

EventEffect
membership_activatedSets user plan + membership ID
membership_deactivatedResets user to free plan
membership_cancel_at_period_end_changedUpdates cancellation flag
payment_succeededSends confirmation (if email configured)
payment_failedSends failure notification (if email configured)

Configuration

GET /api/config/plans

Returns plan configuration for client components.

Auth: None (public — only returns non-sensitive plan metadata) Response: { free: { name, description, priceMonthly, ... }, pro: { ... }, ... }

GET /api/config/accent

Returns the current accent color.

Auth: None Response: { color: "#5b4cff" } or { color: null }

POST /api/config/accent

Saves a new accent color.

Auth: Admin only (403 if not admin) Body: { "color": "#5b4cff" }

GET /api/config/integrations

Returns current integration settings (analytics provider, email provider).

Auth: Admin only

POST /api/config/integrations

Saves integration settings.

Auth: Admin only Body: { "analytics_provider": "posthog", "analytics_id": "phc_xxx", "email_provider": "resend", "email_api_key": "re_xxx" }

Setup

GET /api/setup

Returns current setup status and configured values.

Auth: Open before setup is complete; admin only after.

POST /api/setup

Saves configuration values during setup.

Auth: Open before setup is complete; admin only after. Body: { "configs": { "whop_app_id": "app_xxx", ... } }

POST /api/setup/complete

Marks setup as complete.

Auth: Admin only Response: { success: true }

GET /api/search

Full-text search across documentation pages (powered by Fumadocs).

Auth: None Params: q (search query)

Adding a New API Route

// app/api/your-route/route.ts
import { NextResponse } from "next/server";
import { getSession } from "@/lib/auth";

export async function POST(request: Request) {
  const session = await getSession();
  if (!session) {
    return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
  }

  const body = await request.json();
  // ... your logic

  return NextResponse.json({ success: true });
}

For admin-only routes, check session.isAdmin. For plan-gated routes, use hasMinimumPlan(session.plan, "starter").

On this page