# Stripe Integration Using @supabase/stripe-sync-engine ## ๐Ÿ“ฆ Overview We're using the official [@supabase/stripe-sync-engine](https://github.com/supabase/stripe-sync-engine) library to handle all Stripe webhook processing and data syncing. **Benefits:** - โœ… Battle-tested by Supabase - โœ… Handles all Stripe webhook events automatically - โœ… Automatic schema management - โœ… Real-time sync of Stripe data - โœ… No custom webhook handlers needed ## ๐Ÿš€ Quick Setup ### 1. Install Package ```bash cd apps/api npm install @supabase/stripe-sync-engine ``` ### 2. Configure Environment Add to `api/.env`: ```env # Stripe STRIPE_SECRET_KEY=sk_test_xxxxx STRIPE_WEBHOOK_SECRET=whsec_xxxxx # Database (direct Postgres connection) DATABASE_URL=postgresql://postgres:[password]@db.[project].supabase.co:5432/postgres # Or use Supabase connection string SUPABASE_URL=https://[project].supabase.co SUPABASE_SERVICE_ROLE_KEY=your_service_role_key ``` ### 3. Run Library Migrations The stripe-sync-engine library comes with its own migrations. Run them: ```typescript // In a one-time setup script or manually import { runMigrations } from '@supabase/stripe-sync-engine'; await runMigrations({ databaseUrl: process.env.DATABASE_URL }); ``` Or manually execute the migrations from: `node_modules/@supabase/stripe-sync-engine/dist/migrations/*.sql` ### 4. Integration is Already Done! โœ… The webhook handler in `api/src/stripe.ts` is already configured: ```typescript import { StripeSync } from "@supabase/stripe-sync-engine"; const stripeSync = new StripeSync({ stripeSecretKey: process.env.STRIPE_SECRET_KEY, stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET, schema: "public", poolConfig: { connectionString: process.env.DATABASE_URL, max: 10, }, revalidateObjectsViaStripeApi: ['subscription', 'customer'], }); // Webhook endpoint stripeRouter.post("/webhook", async (c) => { const signature = c.req.header("stripe-signature"); const rawBody = await c.req.text(); await stripeSync.processWebhook(rawBody, signature); return c.json({ received: true }); }); ``` ## ๐Ÿ“Š Database Schema The library creates these tables in the `public` schema (with `stripe_` prefix): ### Core Tables (Auto-created) - `stripe_customers` - `stripe_subscriptions` - `stripe_subscription_items` - `stripe_products` - `stripe_prices` - `stripe_invoices` - `stripe_charges` - `stripe_payment_intents` - `stripe_payment_methods` - And many more... ### Custom Additions (From our SQL) We still need our custom `sql/35_stripe_wrappers.sql` for: - โœ… `profiles.is_paying` column - โœ… `profiles.subscription_tier` column - โœ… Triggers to auto-update profile when subscription changes - โœ… RLS policies - โœ… Helper functions (`is_paying_user()`, etc.) **Note:** Delete `sql/36_stripe_webhooks.sql` - not needed, library handles webhooks! ## ๐Ÿ”„ How It Works ### 1. Webhook Received ``` Stripe โ†’ POST /api/v1/stripe/webhook โ†’ StripeSync.processWebhook() ``` ### 2. Sync Engine Processes ``` 1. Verifies signature 2. Determines event type 3. Syncs to appropriate table (stripe_subscriptions, stripe_customers, etc.) 4. Handles all edge cases automatically ``` ### 3. Our Custom Trigger Fires ``` stripe_subscriptions updated โ†’ Trigger โ†’ profiles.is_paying updated ``` ### 4. Frontend Queries ``` Frontend โ†’ Supabase Client โ†’ stripe_subscriptions (RLS) โ†’ User's data ``` ## โœจ What the Library Handles The stripe-sync-engine automatically handles: - โœ… All webhook event types (100+ events) - โœ… Signature verification - โœ… Idempotency (duplicate events) - โœ… Foreign key relationships - โœ… Deleted entities - โœ… List expansion (fetching all items) - โœ… Backfilling historical data - โœ… Database schema migrations - โœ… Connection pooling - โœ… Error handling ## ๐ŸŽฏ What We Still Handle We only need to maintain: 1. **Custom Profile Fields** - `profiles.is_paying` - `profiles.subscription_tier` 2. **Automatic Update Trigger** ```sql CREATE TRIGGER update_profile_on_subscription_change AFTER INSERT OR UPDATE ON stripe_subscriptions โ†’ Updates profile fields ``` 3. **Action Endpoints** (in `api/src/stripe.ts`) - Create checkout session - Create portal session - Cancel subscription - Reactivate subscription 4. **RLS Policies** - Ensure users only see their own data ## ๐Ÿงช Testing ### Test Webhook Processing ```bash # Terminal 1: Start your API cd apps/api && npm run dev # Terminal 2: Forward Stripe webhooks stripe listen --forward-to http://localhost:3000/api/v1/stripe/webhook # Terminal 3: Trigger test event stripe trigger customer.subscription.created ``` **Watch the magic:** 1. Webhook arrives 2. stripe-sync-engine processes it 3. Data appears in `stripe_subscriptions` table 4. Trigger updates `profiles.is_paying` 5. Frontend sees update immediately ### Verify Sync ```sql -- Check synced subscription SELECT * FROM stripe_subscriptions; -- Check synced customer SELECT * FROM stripe_customers; -- Check profile updated SELECT email, is_paying, subscription_tier FROM profiles; ``` ## ๐Ÿ“ Environment Variables Needed ```env # Required STRIPE_SECRET_KEY=sk_test_xxxxx STRIPE_WEBHOOK_SECRET=whsec_xxxxx DATABASE_URL=postgresql://postgres:password@host:port/db # Optional (if DATABASE_URL not set) SUPABASE_URL=https://xxx.supabase.co SUPABASE_SERVICE_ROLE_KEY=eyJxxx... ``` ## ๐Ÿ”ง Backfilling Historical Data If you have existing Stripe data, backfill it: ```typescript // Run this once to sync all existing data await stripeSync.syncBackfill({ object: 'all', // or specific: 'customer', 'subscription', 'product', etc. created: { gte: 0 // Sync everything from the beginning } }); ``` Or sync specific objects: ```typescript await stripeSync.syncProducts(); await stripeSync.syncPrices(); await stripeSync.syncCustomers(); await stripeSync.syncSubscriptions(); ``` ## ๐Ÿ“š Resources - **Library Repo**: https://github.com/supabase/stripe-sync-engine - **Library Docs**: https://supabase.github.io/stripe-sync-engine - **Our Implementation**: `api/src/stripe.ts` - **Custom SQL**: `sql/35_stripe_wrappers.sql` (profile fields & triggers only) ## โšก Benefits Over Custom Implementation | Feature | Custom | stripe-sync-engine | |---------|--------|-------------------| | Webhook handlers | Manual | โœ… Automatic | | Schema management | Manual | โœ… Automatic | | Edge cases | You handle | โœ… Handled | | Updates | You maintain | โœ… Library updates | | Testing | Your responsibility | โœ… Battle-tested | | Backfilling | Custom scripts | โœ… Built-in | ## ๐ŸŽ‰ Summary **Before:** 267 lines of custom webhook code + SQL handlers **After:** ~20 lines using the library **What you maintain:** - Profile integration (`is_paying`, `subscription_tier`) - Action endpoints (checkout, portal, cancel) - RLS policies - Frontend hooks **What the library handles:** - Everything else! ๐Ÿš€ --- **Status**: โœ… Integrated **Next**: Configure Stripe, test webhooks, add to settings page