HCTHE HCLAB

Commerce setup

Premium content gating and learning path purchases require Stripe. This guide covers what editors need to know; technical env setup is in Environment variables and Production deployment.

What Stripe powers

Flow User entry Result
Premium subscription /pricing or account upgrade User.plan → Premium
Learning path purchase Path detail "Buy" button learningPathPurchase record

Both flows use POST /api/stripe/checkout and confirm via POST /api/stripe/webhook.

Required environment variables

Variable Purpose
STRIPE_SECRET_KEY Server-side API (required at build/runtime)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY Client-side checkout
STRIPE_WEBHOOK_SECRET Verify webhook signatures
STRIPE_PREMIUM_MONTHLY_PRICE_ID Monthly subscription price ID
STRIPE_PREMIUM_ANNUAL_PRICE_ID Annual subscription price ID
NEXT_PUBLIC_SITE_URL Checkout success/cancel redirect URLs

Use test keys locally (sk_test_…, pk_test_…) and live keys in production only on your production host.

Finding API keys (current Stripe Dashboard)

Stripe’s layout changed in 2025–2026. You may see Workbench / Developers in the sidebar, or only Home, Payments, Billing, and More. Use any of these paths:

Goal How to get there
API keys (fastest) Open dashboard.stripe.com/test/apikeys for test keys, or dashboard.stripe.com/apikeys for live keys
From the sidebar MoreDevelopersAPI keys, or top Developers area → API keys
Test vs live Use View test data (top of Dashboard). When on, the API keys page shows sandbox/test keys (pk_test_, sk_test_). When off, you see live keys (pk_live_, sk_live_).

On the API keys page you’ll see two sections:

Section Use for THE HCLAB?
Standard keys Yes — copy Publishable keyNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, and Secret key (click Reveal test key / Reveal live key) → STRIPE_SECRET_KEY
Restricted keys Optional later (rk_…) — scoped permissions; do not substitute for the standard secret key unless you configure the right scopes

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY is the full Publishable key token from the Standard keys table (starts with pk_test_ or pk_live_, usually 50+ characters). It is not a restricted key (rk_…) and not the secret key.

For local development, turn View test data on and use only pk_test_ / sk_test_ in .env. Never use live keys on localhost.

Stripe Dashboard setup

1. Create products and prices

Open Product catalog in the sidebar (or Products in older layouts), then:

  1. Create Premium product
  2. Add recurring prices: monthly and annual
  3. Copy price IDs to STRIPE_PREMIUM_MONTHLY_PRICE_ID and STRIPE_PREMIUM_ANNUAL_PRICE_ID

Learning path purchases do not need pre-created Stripe prices — checkout uses dynamic price_data from the path's CMS price field.

2. Configure webhook

In DevelopersWebhooks (or dashboard.stripe.com/test/webhooks for test mode), Add endpoint:

https://your-domain.com/api/stripe/webhook

Subscribe to events:

  • checkout.session.completed
  • customer.subscription.updated
  • customer.subscription.deleted

Open the endpoint → Signing secret → copy to STRIPE_WEBHOOK_SECRET (whsec_…).

For local testing, use the Stripe CLI (recommended — no Dashboard endpoint needed on localhost):

stripe listen --forward-to localhost:3000/api/stripe/webhook

CMS: learning path pricing

On /admin/learning-paths/new or edit:

Field Behavior
One-time price (USD) Whole dollars (e.g. 49 = $49.00). Stored in cents internally.
Blank price Path cannot be purchased individually — access via plan only
Visibility Still applies — Premium visibility + price means "subscribers OR buyers"

After saving a priced path:

  1. Publish the path
  2. Visit /learning-paths/[slug] as a free member
  3. Click purchase → Stripe Checkout
  4. Complete test payment → redirect with ?purchased=1
  5. Verify access and record on /account

CMS: premium content

Set Visibility → Premium on any gated content type. No per-item Stripe config — one subscription unlocks all Premium-tier content.

Before publishing Premium content:

  • Stripe keys and price IDs configured
  • Webhook endpoint live and receiving events
  • Test subscription on /pricing upgrades a test user to Premium
  • Gated content accessible after upgrade

What happens on payment

Subscription checkout

  1. User clicks upgrade on /pricing
  2. Checkout session created with customer metadata (userId)
  3. Webhook checkout.session.completed → retrieves subscription → sets User.plan = PREMIUM, stores stripeSubscriptionId
  4. Subscription changes/deletions update plan via webhook

Path purchase

  1. Authenticated user buys a priced path
  2. One-time Checkout session with path title and price
  3. Webhook creates learningPathPurchase with amount paid
  4. User gains path access even without Premium plan

Admin visibility

/admin dashboard shows subscription counts and path purchase revenue when data exists.

/admin/users — manually set plan (Free, Subscriber, Premium, Enterprise) for comped access without Stripe.

Member account

/account displays:

  • Current plan badge
  • Upgrade button (free users)
  • Purchased learning paths
  • Path progress and certifications

Editor checklist

Task Where
Set path price /admin/learning-paths → One-time price field
Gate content Any CMS form → Visibility → Premium
Verify purchase flow Public path page → test checkout
Verify subscription /pricing → test checkout
Comp a user /admin/users → set plan to Premium

Related docs