Stripe setup
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.
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. unstorageresolvable by the host app.- The modules installed and configured, as in the quick setup of Stripe:
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
},
})
stripe:event:<event id>. That is why KV is required.Set up Stripe
Add the webhook endpoint
constructEventAsync.- In the Stripe dashboard, open Developers > Webhooks.
- Add an endpoint that points at
https://<your-host>/api/stripe/webhook, or at yoursettings.webhookPath. - Select the events your installed modules need, from the table below.
- Copy the signing secret into
NUXT_STRIPE_WEBHOOK_SECRET.
| Module | Events |
|---|---|
| Payments | checkout.session.completed, checkout.session.async_payment_succeeded, checkout.session.async_payment_failed, checkout.session.expired, charge.refunded |
| Subscriptions | customer.subscription.created, .updated, .deleted, .paused and .resumed |
| Subscriptions with Payments installed | invoice.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.
| Variable | Runtime config | Purpose |
|---|---|---|
NUXT_STRIPE_SECRET_KEY | stripe.secretKey | The server-side secret API key (sk_..., or a restricted key). |
NUXT_STRIPE_WEBHOOK_SECRET | stripe.webhookSecret | The signing secret of the webhook endpoint (whsec_...). |
NUXT_STRIPE_API_VERSION | stripe.apiVersion | Optional. Overrides the pinned API version. |
NUXT_PUBLIC_STRIPE_PUBLISHABLE_KEY | public.stripe.publishableKey | The 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
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.