Going further

Stripe setup

Set up the Stripe dashboard, webhook endpoint, keys and KV once, so Stripe, Payments and Subscriptions all work, in production and locally.

Payments and Subscriptions learn that money moved only when Stripe tells them, through a webhook. Until that endpoint, its events and the keys are set up, a paid checkout changes nothing in your app. This page sets up the Stripe side once, so every commerce module works, in production and in local development.

For: app developers who install Payments, Subscriptions or Events.

The Stripe module owns one verified webhook endpoint. Payments and Subscriptions register listeners on it for the events they need. Stripe stays the source of truth for catalog data. The modules store no products or prices, only the Stripe customer id of each user.

Before you start

  • NuxtHub (@nuxthub/core) with key-value storage (KV) enabled: hub.kv, which is set by default. No extra table is needed.
  • unstorage resolvable by the host app.
  • The modules installed and configured, as in the quick setup of Stripe:
nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxthub/core', '@frigear-nu/users', '@frigear-nu/stripe'],
  hub: { db: { dialect: 'sqlite', driver: 'libsql' }, kv: true },
  stripe: {
    settings: { webhookPath: '/api/stripe/webhook' }, // default
  },
})
Webhook idempotency stores processed event ids in NuxtHub KV, under stripe:event:<event id>. That is why KV is required.

Set up Stripe

Add the webhook endpoint

Put no auth or CSRF middleware in front of the webhook route. Stripe's requests must reach it untouched: the route reads the raw body and verifies the signature itself, with constructEventAsync.
  1. In the Stripe dashboard, open Developers > Webhooks.
  2. Add an endpoint that points at https://<your-host>/api/stripe/webhook, or at your settings.webhookPath.
  3. Select the events your installed modules need, from the table below.
  4. Copy the signing secret into NUXT_STRIPE_WEBHOOK_SECRET.
ModuleEvents
Paymentscheckout.session.completed, checkout.session.async_payment_succeeded, checkout.session.async_payment_failed, checkout.session.expired, charge.refunded
Subscriptionscustomer.subscription.created, .updated, .deleted, .paused and .resumed
Subscriptions with Payments installedinvoice.paid, invoice.payment_failed, invoice.voided and invoice.marked_uncollectible, for subscription invoices

Events sells tickets through Payments, so it needs the Payments events. Without Payments, no invoice event is handled.

Set the keys

Read them through runtime config, never process.env.

VariableRuntime configPurpose
NUXT_STRIPE_SECRET_KEYstripe.secretKeyThe server-side secret API key (sk_..., or a restricted key).
NUXT_STRIPE_WEBHOOK_SECRETstripe.webhookSecretThe signing secret of the webhook endpoint (whsec_...).
NUXT_STRIPE_API_VERSIONstripe.apiVersionOptional. Overrides the pinned API version.
NUXT_PUBLIC_STRIPE_PUBLISHABLE_KEYpublic.stripe.publishableKeyThe publishable key (pk_...), exposed to the client.

Without the secret key, the Stripe client throws 501 not_configured. Without the webhook secret, the endpoint answers 501 not_configured.

Prepare products and billing

This step applies only to Subscriptions. One-time payments need no products or prices: their checkout sessions use inline price_data.

  • Products and prices. Create recurring prices. Use lookup keys to keep config the same across environments, because test and live mode have different price ids. Stripe needs no metadata or copy.
  • Billing portal. In Settings > Billing > Customer portal, enable cancellation and payment method updates. Enable subscription updates only with allowChangeInPortal: true, and list the prices the portal may switch between.

Local development

Forward events to your dev server with the Stripe CLI. Use the secret it prints as NUXT_STRIPE_WEBHOOK_SECRET:

stripe listen --forward-to localhost:3000/api/stripe/webhook
What you should see: after a test checkout, stripe listen shows the events with status 200, and the endpoint answers { received: true }.

Next steps

  • Sell event tickets – use this setup end to end.
  • Stripe – what the webhook answers, how retries work and how to listen to events.
Copyright © 2026