Stripe Webhooks
Stripe webhooks are the bridge between completed Stripe actions and the local product state inside NuxtBase.
Without them, checkout may succeed in Stripe while the dashboard still looks unchanged.
What The Webhook Endpoint Does
Section titled “What The Webhook Endpoint Does”The template handles billing events at:
/api/billing/webhookThe endpoint expects:
POSTrequests only- the raw request body
- a valid
stripe-signatureheader
If signature verification fails, the request is rejected before any billing state is updated.
Event Types The Template Handles
Section titled “Event Types The Template Handles”The shipped webhook code processes these Stripe events:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.pausedcustomer.subscription.resumedcustomer.subscription.deletedinvoice.payment_succeededinvoice.paidinvoice.payment_failedinvoice.voidedcharge.refunded
Unhandled events are ignored safely.
Why checkout.session.completed Matters
Section titled “Why checkout.session.completed Matters”Checkout completion is where the template links a Stripe customer back to the organization that started checkout.
That link depends on client_reference_id, which the app sets to the active
organization ID when creating the checkout session.
If that organization link is missing, later subscription events have nothing local to attach to.
Subscription Sync Behavior
Section titled “Subscription Sync Behavior”When Stripe sends a subscription change event, the template:
- finds the local billing customer from the Stripe customer ID
- resolves the Stripe price back to an internal plan key
- upserts the local subscription record
- updates effective plan-linked quota state
- may send notification email to organization owners
- may dispatch an outbound webhook for your product
This is why plan mapping must stay aligned with your env price IDs.
Dedupe And Retry Behavior
Section titled “Dedupe And Retry Behavior”The webhook layer keeps a billingEventLog record for each provider event.
That gives the template two important protections:
- duplicate Stripe deliveries do not create duplicate billing side effects
- transient failures can be retried cleanly
When handler execution fails, the endpoint returns 500 so Stripe retries the
event. That is intentional.
Invoice And Refund Mirroring
Section titled “Invoice And Refund Mirroring”NuxtBase does not only track subscription rows. It also mirrors invoice and refund events into local billing tables.
That gives the app a local operational history for:
- paid invoices
- failed invoices
- voided invoices
- refunded charges
You do not need to query Stripe live on every dashboard render to understand basic billing state.
Local Development Reality
Section titled “Local Development Reality”If webhook verification suddenly starts failing during local work, check whether your Stripe CLI listener was restarted. A new listener session usually means a new signing secret.
The setup instructions for forwarding and refreshing
NUXT_STRIPE_WEBHOOK_SECRET are covered in setup/billing-setup.