2025-11-03 08:46:10 +00:00
# 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
2025-11-10 07:53:03 +00:00
cd apps/api
2025-11-03 08:46:10 +00:00
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
2025-11-10 07:53:03 +00:00
cd apps/api & & npm run dev
2025-11-03 08:46:10 +00:00
# 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
2025-11-10 07:53:03 +00:00
2025-11-13 08:24:23 +00:00
2025-11-18 16:09:10 +00:00
2025-11-19 21:24:23 +00:00