6.9 KiB
Stripe Integration Using @supabase/stripe-sync-engine
📦 Overview
We're using the official @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
cd api
npm install @supabase/stripe-sync-engine
2. Configure Environment
Add to api/.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:
// 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:
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_customersstripe_subscriptionsstripe_subscription_itemsstripe_productsstripe_pricesstripe_invoicesstripe_chargesstripe_payment_intentsstripe_payment_methods- And many more...
Custom Additions (From our SQL)
We still need our custom sql/35_stripe_wrappers.sql for:
- ✅
profiles.is_payingcolumn - ✅
profiles.subscription_tiercolumn - ✅ 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:
-
Custom Profile Fields
profiles.is_payingprofiles.subscription_tier
-
Automatic Update Trigger
CREATE TRIGGER update_profile_on_subscription_change AFTER INSERT OR UPDATE ON stripe_subscriptions → Updates profile fields -
Action Endpoints (in
api/src/stripe.ts)- Create checkout session
- Create portal session
- Cancel subscription
- Reactivate subscription
-
RLS Policies
- Ensure users only see their own data
🧪 Testing
Test Webhook Processing
# Terminal 1: Start your API
cd 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:
- Webhook arrives
- stripe-sync-engine processes it
- Data appears in
stripe_subscriptionstable - Trigger updates
profiles.is_paying - Frontend sees update immediately
Verify Sync
-- 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
# 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:
// 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:
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