Next.js SaaS License Starter
Clone-and-run Next.js app with Keymint license management pre-configured. Setup page, license API route, and webhook handling included.
Quick Start
git clone https://github.com/keymint-dev/keymint-nextjs-starter.git
cd keymint-nextjs-starter
npm install
cp .env.example .env.local
npm run devOpens a Next.js app at localhost:3000. /dashboard/licenses is a static page with setup steps. Create a license by sending POST /api/licenses with a customerEmail and an Authorization: Bearer $LICENSE_API_SECRET header; create products and monitor activations in the Keymint Dashboard.
What's Included
- License dashboard — Starter dashboard page with setup instructions
- Key generation — API route for creating license keys with customer details, protected by a shared secret
- Webhook receiver — Verified Keymint outbound webhook handler with HMAC-SHA256 signature verification
- License service — Server-side wrapper for create, block, unblock, query, and validate operations
Configuration
KEYMINT_ADMIN_API_KEY=km_live_your_admin_key
KEYMINT_CLIENT_API_KEY=km_live_your_client_key
KEYMINT_PRODUCT_ID=YOUR_PRODUCT_ID
KEYMINT_WEBHOOK_SECRET=your_webhook_signing_secret
LICENSE_API_SECRET=your_shared_secret| Variable | Scope | Where to Find |
|---|---|---|
KEYMINT_ADMIN_API_KEY | Server | Dashboard → Developer → API Keys (admin scope) |
KEYMINT_CLIENT_API_KEY | Server | Dashboard → Developer → API Keys (client scope) |
KEYMINT_PRODUCT_ID | Server | Dashboard → Products |
KEYMINT_WEBHOOK_SECRET | Server | Dashboard → Developer → Webhooks → your endpoint |
LICENSE_API_SECRET | Server | You choose it. Generate one with openssl rand -hex 32 |
Project Structure
src/
├── app/
│ ├── page.tsx # Landing page
│ ├── layout.tsx # Root layout
│ ├── api/
│ │ ├── licenses/route.ts # License creation endpoint
│ │ └── webhooks/keymint/route.ts # Keymint webhook receiver
│ └── dashboard/
│ └── licenses/page.tsx # Static setup-instructions page
└── lib/
├── license-service.ts # Keymint API wrapper
└── require-secret.ts # Bearer-secret check for POST /api/licensesAPI Methods Used
| Function | Where | Scope | Purpose |
|---|---|---|---|
createCustomerLicense() | license-service.ts | admin | Create a license with customer details |
blockLicense() | license-service.ts | admin | Block a license key |
unblockLicense() | license-service.ts | admin | Unblock a license key |
getLicenseInfo() | license-service.ts | admin | Query license details |
validateLicense() | license-service.ts | client | Validate/activate a license |
Deploy
npm run build
# Deploy to Vercel, Railway, or any Node.js hostSet the KEYMINT_WEBHOOK_SECRET as the signing secret for your Keymint webhook endpoint. The URL should be https://yourdomain.com/api/webhooks/keymint.
POST /api/licenses uses your admin key, so it only accepts requests with Authorization: Bearer $LICENSE_API_SECRET and is meant to be called from your own backend. The license route and the webhook route both refuse requests until their secret is set. In production, create licenses from your payment provider's webhook after a successful checkout instead of exposing this route.
Next Steps
- Add Stripe subscription licensing for automated key provisioning
- Add a database (Drizzle, Prisma) to persist license and customer records
- Add customer self-service portal for license management
- Configure Keymint webhooks to point to
/api/webhooks/keymint