stripe-supabase-webhooks — implementing stripe webhooks in next.js stripe-supabase-webhooks, firstserveseattle, community, implementing stripe webhooks in next.js, ide skills, supabase subscription state syncing, next.js app router stripe integration, transactional email integration with stripe, Claude Code, Cursor, Windsurf

v1.0.0
GitHub

About this Skill

Perfect for E-commerce Agents needing robust Stripe webhook handling and Supabase integration. stripe-supabase-webhooks is a skill providing patterns for implementing robust Stripe webhook handlers in Next.js App Router applications that sync subscription state to Supabase.

Features

Implements signature verification for secure Stripe webhook handling
Dispatches events for intelligent upsert strategies in Supabase
Supports transactional email integration for automated notifications
Utilizes Next.js App Router for scalable and performant webhook handling
Syncs subscription state to Supabase for real-time data tracking
Provides patterns for robust Stripe webhook handlers in TypeScript

# Core Topics

rrh1441 rrh1441
[0]
[0]
Updated: 3/8/2026

Agent Capability Analysis

The stripe-supabase-webhooks skill by rrh1441 is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance. Optimized for implementing stripe webhooks in next.js, supabase subscription state syncing, next.js app router stripe integration.

Ideal Agent Persona

Perfect for E-commerce Agents needing robust Stripe webhook handling and Supabase integration.

Core Value

Empowers agents to implement signature verification, event dispatching, and intelligent upsert strategies using Stripe and Supabase, streamlining subscription state management and transactional email integration with Next.js App Router applications.

Capabilities Granted for stripe-supabase-webhooks

Implementing secure Stripe webhook handlers with signature verification
Syncing subscription states to Supabase for scalable e-commerce solutions
Integrating transactional emails with Stripe webhooks and Supabase

! Prerequisites & Limits

  • Requires Stripe and Supabase accounts
  • Next.js App Router application required
  • Limited to Stripe and Supabase integrations
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

stripe-supabase-webhooks

Install stripe-supabase-webhooks, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command...

SKILL.md
Readonly

Stripe Supabase Webhooks

Overview

This skill provides patterns for implementing robust Stripe webhook handlers in Next.js App Router applications that sync subscription state to Supabase. It covers signature verification, event dispatching, intelligent upsert strategies, and transactional email integration.

Core Patterns

1. Route Handler Setup

typescript
1// app/api/stripe-webhook/route.ts 2import { NextRequest, NextResponse } from 'next/server'; 3import Stripe from 'stripe'; 4import { createClient } from '@supabase/supabase-js'; 5 6export const dynamic = 'force-dynamic'; // Disable edge caching 7 8const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { 9 apiVersion: '2025-01-27.acacia' as Stripe.LatestApiVersion, 10}); 11 12const supa = createClient( 13 process.env.NEXT_PUBLIC_SUPABASE_URL!, 14 process.env.SUPABASE_SERVICE_ROLE_KEY!, // Use service role for webhooks 15);

2. Webhook Signature Verification

Always verify signatures before processing:

typescript
1export async function POST(req: NextRequest) { 2 const rawBody = Buffer.from(await req.arrayBuffer()); 3 const sig = req.headers.get('stripe-signature') ?? ''; 4 5 let event: Stripe.Event; 6 try { 7 event = stripe.webhooks.constructEvent( 8 rawBody, 9 sig, 10 process.env.STRIPE_WEBHOOK_SECRET!, 11 ); 12 } catch (err) { 13 console.warn('Signature verification failed:', err); 14 return NextResponse.json({ error: 'Invalid signature' }, { status: 400 }); 15 } 16 17 // Process event... 18 return NextResponse.json({ received: true }); 19}

3. Cascading Upsert Strategy

When syncing Stripe data to Supabase, use a cascading lookup strategy to handle various user identification scenarios:

typescript
1async function upsertSubscriber(fields: { 2 stripeCustomerId: string; 3 stripeSubscriptionId?: string; 4 userId?: string; // From auth 5 email?: string; // From Stripe customer 6 plan?: string; 7 status?: Stripe.Subscription.Status | 'expired'; 8 hasCard?: boolean; 9 trialEnd?: number | null; 10}) { 11 const updateData = { 12 stripe_customer_id: fields.stripeCustomerId, 13 stripe_subscription_id: fields.stripeSubscriptionId, 14 email: fields.email, 15 plan: fields.plan, 16 status: fields.status, 17 has_card: fields.hasCard, 18 trial_end: fields.trialEnd, 19 updated_at: new Date().toISOString(), 20 }; 21 22 // Priority 1: Update by user_id (most reliable for authenticated users) 23 if (fields.userId) { 24 const { data: existing } = await supa 25 .from('subscribers') 26 .select('id') 27 .eq('user_id', fields.userId) 28 .maybeSingle(); 29 30 if (existing) { 31 await supa.from('subscribers').update(updateData).eq('user_id', fields.userId); 32 return; 33 } 34 } 35 36 // Priority 2: Update by email (handles pre-signup records) 37 if (fields.email) { 38 const { data: existing } = await supa 39 .from('subscribers') 40 .select('id') 41 .eq('email', fields.email) 42 .maybeSingle(); 43 44 if (existing) { 45 await supa.from('subscribers').update(updateData).eq('email', fields.email); 46 return; 47 } 48 } 49 50 // Priority 3: Upsert by stripe_customer_id (fallback) 51 await supa 52 .from('subscribers') 53 .upsert(updateData, { onConflict: 'stripe_customer_id' }); 54}

4. Event Type Handling

Handle subscription lifecycle events with proper customer data retrieval:

typescript
1switch (event.type) { 2 case 'checkout.session.completed': { 3 const session = event.data.object as Stripe.Checkout.Session; 4 const custId = session.customer as string; 5 const subId = session.subscription as string; 6 7 const customer = await stripe.customers.retrieve(custId) as Stripe.Customer; 8 const subscription = await stripe.subscriptions.retrieve(subId); 9 10 await upsertSubscriber({ 11 stripeCustomerId: custId, 12 stripeSubscriptionId: subId, 13 userId: session.metadata?.userId || session.client_reference_id, 14 email: customer.email ?? session.customer_details?.email ?? '', 15 plan: planFromPrice(subscription.items.data[0]?.price.id ?? ''), 16 status: subscription.status, 17 hasCard: true, 18 trialEnd: subscription.trial_end, 19 }); 20 21 // Send welcome email 22 if (customer.email) { 23 await EmailService.sendWelcomeEmail(customer.email, plan); 24 } 25 break; 26 } 27 28 case 'customer.subscription.updated': { 29 const sub = event.data.object as Stripe.Subscription; 30 const customer = await stripe.customers.retrieve(sub.customer as string) as Stripe.Customer; 31 32 await upsertSubscriber({ 33 stripeCustomerId: sub.customer as string, 34 stripeSubscriptionId: sub.id, 35 email: customer.email ?? '', 36 plan: planFromPrice(sub.items.data[0]?.price.id ?? ''), 37 status: sub.status, 38 hasCard: cardOnFile(customer), 39 trialEnd: sub.trial_end, 40 }); 41 break; 42 } 43 44 case 'customer.subscription.deleted': { 45 const sub = event.data.object as Stripe.Subscription; 46 await upsertSubscriber({ 47 stripeCustomerId: sub.customer as string, 48 stripeSubscriptionId: sub.id, 49 status: 'canceled', 50 hasCard: false, 51 }); 52 break; 53 } 54 55 case 'invoice.payment_succeeded': 56 case 'invoice.payment_failed': { 57 const inv = event.data.object as Stripe.Invoice; 58 const customer = await stripe.customers.retrieve(inv.customer as string) as Stripe.Customer; 59 60 await upsertSubscriber({ 61 stripeCustomerId: inv.customer as string, 62 stripeSubscriptionId: inv.subscription as string | undefined, 63 email: customer.email ?? '', 64 status: inv.status as Stripe.Subscription.Status, 65 }); 66 break; 67 } 68}

5. Helper Functions

typescript
1/** Check if customer has payment method on file */ 2function cardOnFile(cust: Stripe.Customer): boolean { 3 return Boolean( 4 cust.invoice_settings?.default_payment_method || cust.default_source 5 ); 6} 7 8/** Map Stripe price ID to internal plan name */ 9function planFromPrice(priceId: string): string { 10 const PRICE_MAP: Record<string, string> = { 11 [process.env.STRIPE_MONTHLY_PRICE_ID!]: 'monthly', 12 [process.env.STRIPE_ANNUAL_PRICE_ID!]: 'annual', 13 }; 14 return PRICE_MAP[priceId] ?? 'unknown'; 15}

Key Events to Handle

EventWhen It FiresAction
checkout.session.completedCustomer completes checkoutCreate/update subscriber, send welcome email
customer.subscription.updatedAny subscription changeSync status, plan, trial_end
customer.subscription.deletedSubscription canceled/expiredMark as canceled
payment_method.attachedCard addedUpdate has_card flag
customer.updatedCustomer email/payment changesSync email and card status
invoice.payment_succeededSuccessful renewalUpdate status
invoice.payment_failedFailed paymentUpdate status, send failure email

Database Schema Requirements

sql
1CREATE TABLE subscribers ( 2 id UUID PRIMARY KEY DEFAULT gen_random_uuid(), 3 user_id UUID UNIQUE REFERENCES auth.users(id), 4 email TEXT, 5 stripe_customer_id TEXT UNIQUE, 6 stripe_subscription_id TEXT, 7 plan TEXT CHECK (plan IN ('monthly', 'annual', 'unknown')), 8 status TEXT, 9 has_card BOOLEAN DEFAULT false, 10 trial_end BIGINT, 11 created_at TIMESTAMPTZ DEFAULT now(), 12 updated_at TIMESTAMPTZ DEFAULT now() 13); 14 15CREATE INDEX idx_subscribers_email ON subscribers(email); 16CREATE INDEX idx_subscribers_stripe_customer ON subscribers(stripe_customer_id);

Environment Variables

env
1STRIPE_SECRET_KEY=sk_live_... 2STRIPE_WEBHOOK_SECRET=whsec_... 3STRIPE_MONTHLY_PRICE_ID=price_... 4STRIPE_ANNUAL_PRICE_ID=price_... 5NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co 6SUPABASE_SERVICE_ROLE_KEY=eyJ...

Testing Webhooks Locally

bash
1# Install Stripe CLI 2brew install stripe/stripe-cli/stripe 3 4# Forward webhooks to local dev server 5stripe listen --forward-to localhost:3000/api/stripe-webhook 6 7# Trigger test events 8stripe trigger checkout.session.completed 9stripe trigger customer.subscription.updated 10stripe trigger invoice.payment_failed

References

See references/event-handling.md for detailed event payload examples and edge cases.

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is stripe-supabase-webhooks?

Perfect for E-commerce Agents needing robust Stripe webhook handling and Supabase integration. stripe-supabase-webhooks is a skill providing patterns for implementing robust Stripe webhook handlers in Next.js App Router applications that sync subscription state to Supabase.

How do I install stripe-supabase-webhooks?

Run the command: npx killer-skills add rrh1441/firstserveseattle/stripe-supabase-webhooks. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for stripe-supabase-webhooks?

Key use cases include: Implementing secure Stripe webhook handlers with signature verification, Syncing subscription states to Supabase for scalable e-commerce solutions, Integrating transactional emails with Stripe webhooks and Supabase.

Which IDEs are compatible with stripe-supabase-webhooks?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for stripe-supabase-webhooks?

Requires Stripe and Supabase accounts. Next.js App Router application required. Limited to Stripe and Supabase integrations.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add rrh1441/firstserveseattle/stripe-supabase-webhooks. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use stripe-supabase-webhooks immediately in the current project.

Related Skills

Looking for an alternative to stripe-supabase-webhooks or another community skill for your workflow? Explore these related open-source skills.

View All

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI