Webhook Handlers for SaaS
Handle webhooks from Stripe and Clerk for subscription and auth events.
Prompt
Implement complete webhook handlers for a SaaS application integrating Stripe for payments/subscriptions and Clerk for authentication with the following requirements:
Application Overview
SaaS Application Details
- Application Name: [e.g., MyApp, SaaS Platform]
- Framework: [Next.js / Express / NestJS / Remix / Custom]
- Database: [PostgreSQL / MySQL / MongoDB / Supabase / PlanetScale]
- ORM: [Prisma / Drizzle / TypeORM / Mongoose / Raw SQL]
- Deployment: [Vercel / Railway / AWS / Custom]
Integration Scope
- Stripe Integration: [Yes / No]
- Clerk Integration: [Yes / No]
- Other Webhooks: [List any additional webhook providers]
Stripe Webhook Configuration
Stripe Setup
- Stripe Mode: [Test mode / Live mode / Both]
- Stripe Products: [List products/plans]
- Billing Model: [Subscription / One-time / Both]
- Currency: [USD / EUR / GBP / Multiple]
Subscription Plans
Define your subscription tiers:
Plan 1: [Name, e.g., Free]
- Stripe Price ID: [price_xxx or placeholder]
- Amount: [0 / 9.99 / Custom]
- Interval: [month / year / one-time]
- Features: [List features for this plan]
- User Limits: [Max users, projects, etc.]
Plan 2: [Name, e.g., Pro]
- Stripe Price ID: [Price ID]
- Amount: [Amount]
- Interval: [Interval]
- Features: [Features]
- User Limits: [Limits]
Plan 3: [Name, e.g., Enterprise]
- Stripe Price ID: [Price ID]
- Amount: [Amount]
- Interval: [Interval]
- Features: [Features]
- User Limits: [Limits]
[Define 2-5 plans]
Stripe Events to Handle
Subscription Events
-
customer.subscription.created:
- Action: [Create subscription record in database]
- Update User: [Set plan, enable features, update status]
- Notifications: [Send welcome email / None]
- Additional Logic: [Custom logic]
-
customer.subscription.updated:
- Action: [Update subscription record]
- Handle Changes: [Plan upgrade/downgrade, quantity change, status change]
- Notifications: [Email on plan change / None]
- Additional Logic: [Custom logic]
-
customer.subscription.deleted:
- Action: [Mark subscription as canceled]
- Update User: [Downgrade to free, disable features]
- Data Retention: [Keep data / Delete after X days / Archive]
- Notifications: [Cancellation email / None]
Payment Events
-
invoice.payment_succeeded:
- Action: [Record payment, extend subscription]
- Update User: [Renew access, reset usage limits]
- Notifications: [Receipt email / None]
- Additional Logic: [Custom logic]
-
invoice.payment_failed:
- Action: [Record failed payment]
- Update User: [Grace period / Immediate suspension]
- Notifications: [Payment failed email / None]
- Retry Logic: [Stripe handles / Custom]
-
payment_intent.succeeded:
- Action: [For one-time payments]
- Update User: [Grant access, credits, etc.]
- Notifications: [Confirmation email / None]
Customer Events
-
customer.created:
- Action: [Store customer ID with user]
- Additional Logic: [Custom logic]
-
customer.updated:
- Action: [Update customer details]
- Sync Fields: [Email, name, metadata]
-
customer.deleted:
- Action: [Handle customer deletion]
- Data Cleanup: [Remove references / Archive]
[Define additional Stripe events if needed]
Database Schema for Stripe
Subscriptions Table
- id: [Primary key]
- userId: [Foreign key to users]
- stripeSubscriptionId: [Stripe subscription ID]
- stripeCustomerId: [Stripe customer ID]
- stripePriceId: [Price ID]
- status: [active, canceled, past_due, etc.]
- currentPeriodStart: [Timestamp]
- currentPeriodEnd: [Timestamp]
- cancelAtPeriodEnd: [Boolean]
- createdAt: [Timestamp]
- updatedAt: [Timestamp]
Payments Table (optional)
- id: [Primary key]
- userId: [Foreign key]
- stripeInvoiceId: [Invoice ID]
- amount: [Amount paid]
- currency: [Currency]
- status: [paid, failed, etc.]
- createdAt: [Timestamp]
Clerk Webhook Configuration
Clerk Setup
- Clerk Instance: [Production / Development / Both]
- User Metadata: [Custom fields to sync]
- Organization Support: [Yes / No]
Clerk Events to Handle
User Events
-
user.created:
- Action: [Create user record in database]
- Fields to Store: [id, email, firstName, lastName, imageUrl, etc.]
- Default Values: [Set default plan, credits, etc.]
- Notifications: [Welcome email / None]
- Additional Logic: [Create Stripe customer / Custom]
-
user.updated:
- Action: [Update user record]
- Sync Fields: [Email, name, profile image, metadata]
- Handle Changes: [Email change, profile updates]
- Additional Logic: [Update Stripe customer / Custom]
-
user.deleted:
- Action: [Soft delete / Hard delete user]
- Cascade: [Delete subscriptions, data, etc.]
- Data Retention: [Archive data / Immediate deletion]
- Cleanup: [Cancel Stripe subscription / Custom]
Session Events (optional)
-
session.created:
- Action: [Track user sessions / None]
- Analytics: [Log session start / None]
-
session.ended:
- Action: [Track session end / None]
- Analytics: [Log session duration / None]
Organization Events (if using orgs)
-
organization.created:
- Action: [Create organization record]
- Default Settings: [Plan, limits, etc.]
-
organization.updated:
- Action: [Update organization]
- Sync Fields: [Name, metadata, etc.]
-
organization.deleted:
- Action: [Delete organization and members]
- Cascade: [Handle member cleanup]
-
organizationMembership.created:
- Action: [Add user to organization]
- Permissions: [Set role, permissions]
-
organizationMembership.deleted:
- Action: [Remove user from organization]
- Cleanup: [Revoke access]
Database Schema for Clerk
Users Table
- id: [Clerk user ID as primary key]
- email: [Email address]
- firstName: [First name]
- lastName: [Last name]
- imageUrl: [Profile image]
- plan: [free, pro, enterprise]
- stripeCustomerId: [Link to Stripe]
- createdAt: [Timestamp]
- updatedAt: [Timestamp]
Organizations Table (if using orgs)
- id: [Clerk org ID]
- name: [Organization name]
- plan: [Organization plan]
- stripeCustomerId: [Stripe customer for org]
- createdAt: [Timestamp]
- updatedAt: [Timestamp]
Webhook Endpoint Implementation
Stripe Endpoint
- Path: [/api/webhooks/stripe / /webhooks/stripe]
- Method: [POST]
- Body Parser: [express.raw() for signature verification]
- Signature Verification: [Use stripe.webhooks.constructEvent()]
- Error Handling: [400 for invalid signature, 500 for processing errors]
- Response: [200 with {received: true}]
Clerk Endpoint
- Path: [/api/webhooks/clerk / /webhooks/clerk]
- Method: [POST]
- Body Parser: [JSON]
- Signature Verification: [Use Svix webhook verification]
- Error Handling: [400 for invalid signature, 500 for processing errors]
- Response: [200 with {success: true}]
Business Logic
Subscription Lifecycle
New Subscription
- Stripe Event: customer.subscription.created
- Database: Create subscription record
- User Update: Set plan, enable features
- Notifications: Send welcome email
- Additional: [Custom onboarding, setup, etc.]
Subscription Update
- Stripe Event: customer.subscription.updated
- Detect Change: [Upgrade, downgrade, quantity, status]
- Database: Update subscription record
- User Update: Adjust features, limits
- Notifications: [Email if plan changed]
Subscription Cancellation
- Stripe Event: customer.subscription.deleted
- Database: Update subscription status
- User Update: Downgrade to free plan
- Data Handling: [Archive, delete, or retain]
- Notifications: Cancellation confirmation
Payment Success
- Stripe Event: invoice.payment_succeeded
- Database: Record payment
- User Update: Extend subscription period
- Notifications: Send receipt
Payment Failure
- Stripe Event: invoice.payment_failed
- Database: Record failed payment
- User Update: [Grace period or suspend]
- Notifications: Payment failed alert
- Retry: [Stripe automatic retry]
User Lifecycle
User Registration
- Clerk Event: user.created
- Database: Create user record
- Stripe: Create customer (if needed)
- Defaults: Set free plan, initial credits
- Notifications: Welcome email
User Profile Update
- Clerk Event: user.updated
- Database: Update user fields
- Stripe: Sync customer data (if changed)
User Deletion
- Clerk Event: user.deleted
- Stripe: Cancel subscriptions
- Database: Soft delete or hard delete
- Cleanup: Remove user data per retention policy
Error Handling & Reliability
Idempotency
- Event ID Tracking: [Store processed Stripe event IDs]
- Storage: [Redis / Database table]
- TTL: [7 days / 30 days]
- Duplicate Handling: [Return 200 if already processed]
Error Recovery
- Database Errors: [Retry with exponential backoff / Alert]
- External API Errors: [Retry / Queue for manual review]
- Partial Failures: [Rollback transaction / Continue]
- Logging: [Log all errors with event details]
Monitoring
- Metrics:
- Webhooks received per provider
- Processing success/failure rate
- Processing duration
- Failed event count
- Alerts:
- Signature verification failures
- Processing failures > X%
- Webhook endpoint down
Testing
Test Events
- Stripe CLI: [Use Stripe CLI to send test events]
- Clerk Dashboard: [Send test events from Clerk dashboard]
- Mock Payloads: [Create mock event payloads for testing]
Test Cases
-
Stripe:
- New subscription creation
- Subscription upgrade/downgrade
- Subscription cancellation
- Successful payment
- Failed payment
- Invalid signature
-
Clerk:
- User creation
- User update
- User deletion
- Invalid signature
Code Generation Requirements
Generate a complete SaaS webhook integration including:
-
Webhook Endpoints:
- Stripe webhook endpoint with raw body parsing
- Clerk webhook endpoint with JSON parsing
- Signature verification for both
- Event routing to handlers
- Error handling and responses
-
Stripe Event Handlers:
- Handler for each subscription event
- Handler for each payment event
- Handler for customer events
- Database operations (create, update, delete)
- User feature updates
- Email notifications
-
Clerk Event Handlers:
- Handler for user.created
- Handler for user.updated
- Handler for user.deleted
- Handler for organization events (if applicable)
- Database synchronization
- Stripe customer creation/updates
-
Database Schema:
- Prisma/Drizzle schema for users
- Schema for subscriptions
- Schema for payments (optional)
- Schema for organizations (if applicable)
- Migrations
-
Business Logic:
- Subscription lifecycle management
- Plan upgrade/downgrade logic
- Feature enablement based on plan
- Payment processing
- User onboarding flow
-
Idempotency Layer:
- Event ID tracking (Redis or database)
- Duplicate detection
- TTL-based cleanup
-
Email Notifications:
- Welcome email template
- Subscription confirmation
- Payment receipt
- Payment failed alert
- Cancellation confirmation
-
Testing Suite:
- Unit tests for each event handler
- Integration tests with mock webhooks
- Test utilities for generating signatures
- Sample event payloads
-
Configuration:
- Environment variables
- Stripe webhook secret
- Clerk webhook secret
- Database connection
- Email service configuration
-
Documentation:
- Webhook setup guide
- Event handling flow diagrams
- Database schema documentation
- Testing guide
- Troubleshooting guide
Output production-ready SaaS webhook integration following best practices with:
- Secure signature verification for both Stripe and Clerk
- Idempotent event processing
- Comprehensive error handling
- Database transactions for data consistency
- Email notifications for key events
- Proper plan and feature management
- User and subscription lifecycle handling
- Testing utilities and mock data
- Clear documentation
- Monitoring and alerting setup