# Stripe Integration - Quick Reference ## ๐Ÿš€ Quick Start (For Your Node.js API) ### 1. Install Dependencies ```bash cd apps/api && npm install stripe @stripe/stripe-js cd apps/main && npm install @stripe/stripe-js ``` ### 2. Environment Variables **API (`.env`):** ```env STRIPE_SECRET_KEY=sk_test_xxxxx STRIPE_WEBHOOK_SECRET=whsec_xxxxx SUPABASE_SERVICE_ROLE_KEY=your_service_key FRONTEND_URL=http://localhost:5173 ``` **Frontend (`apps/main/.env`):** ```env VITE_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxx ``` ### 3. Stripe Dashboard Setup 1. Create product named **"Standard"** 2. Add pricing (save price IDs) 3. Add webhook: `https://your-api.com/api/v1/stripe/webhook` 4. Copy webhook secret ### 4. Run Migrations ```sql -- Execute in Supabase SQL Editor \i sql/35_stripe_wrappers.sql \i sql/36_stripe_webhooks.sql ``` ## ๐Ÿ“‹ API Endpoints (Actions Only) | Method | Endpoint | Auth | Description | |--------|----------|------|-------------| | POST | `/api/v1/stripe/webhook` | โŒ | Stripe webhook (signature verified) | | POST | `/api/v1/stripe/create-checkout-session` | โœ… | Start subscription flow | | POST | `/api/v1/stripe/create-portal-session` | โœ… | Open customer portal | | POST | `/api/v1/stripe/cancel-subscription` | โœ… | Cancel subscription | | POST | `/api/v1/stripe/reactivate-subscription` | โœ… | Reactivate subscription | **Note:** Reading subscription data (status, prices, etc.) is done directly via Supabase client from the frontend. ## ๐ŸŽฃ Frontend Hooks ```typescript import { // Direct Supabase queries (RLS-protected, no API call) useSubscription, // Get full subscription from Supabase useIsPayingUser, // Get is_paying from user profile useStripePrices, // Get prices from Supabase // API calls (for Stripe actions) useCreateCheckoutSession, // Create checkout & redirect useCreatePortalSession, // Open customer portal useCancelSubscription, // Cancel at period end useReactivateSubscription // Undo cancellation } from '@/hooks/stripe'; ``` **Benefits of Direct Supabase Access:** - โšก **Faster**: No API hop for reads - ๐Ÿ”’ **Secure**: RLS policies protect data - ๐Ÿ“Š **Real-time**: Can subscribe to changes ## ๐Ÿ’ก Common Use Cases ### Check if User is Paying ```typescript const user = useUser(); if (user.is_paying) { // Show premium feature } ``` ### Subscribe to Standard Plan ```typescript const { mutate: checkout } = useCreateCheckoutSession(); ``` ### Manage Subscription ```typescript const { mutate: openPortal } = useCreatePortalSession(); ``` ### Show Subscription Status ```typescript const { data: subscription } = useSubscription(); {subscription?.status === 'active' && (
Active until {subscription.current_period_end} {subscription.cancel_at_period_end && ( Will cancel at period end )}
)} ``` ## ๐Ÿ” Database Queries ### Frontend Queries (Using Supabase Client) ```typescript // Get user's subscription const { data } = await supabase .from('stripe_subscriptions') .select('*, price:stripe_prices(*, product:stripe_products(*))') .eq('user_id', userId) .single(); // Get available prices const { data } = await supabase .from('stripe_prices') .select('*, product:stripe_products!inner(*)') .eq('active', true) .eq('product.name', 'Standard'); ``` ### Backend SQL Queries ```sql -- Is user paying? SELECT is_paying_user('user-uuid-here'); -- Get subscription details SELECT * FROM get_user_subscription_status('user-uuid-here'); -- Get current user's active subscription (secure, RLS-compliant) SELECT * FROM get_my_active_subscription(); ``` ## ๐ŸŽจ Profile Fields After subscription sync, profiles have: ```typescript { is_paying: boolean, // true if active/trialing subscription subscription_tier: string, // 'free' | 'standard' } ``` ## ๐Ÿงช Test Cards | Card | Result | |------|--------| | `4242 4242 4242 4242` | โœ… Success | | `4000 0000 0000 0002` | โŒ Declined | | `4000 0000 0000 9995` | โŒ Insufficient funds | ## ๐Ÿ”” Webhook Events Handled - โœ… `customer.created` - โœ… `customer.updated` - โœ… `customer.deleted` - โœ… `customer.subscription.created` - โœ… `customer.subscription.updated` - โœ… `customer.subscription.deleted` - โœ… `product.created` / `updated` / `deleted` - โœ… `price.created` / `updated` / `deleted` ## ๐ŸŽฏ Standard Plan Details **Single Tier Model:** - **Free**: Default (no subscription) - **Standard**: Paid subscription **Subscription automatically:** - Sets `is_paying = true` - Sets `subscription_tier = 'standard'` - Updates on webhook events - Reverts to free on cancellation ## ๐Ÿ” Security - โœ… Webhook signature verification - โœ… Row Level Security on all tables - โœ… Users can only see their own subscriptions - โœ… Service role for webhook functions - โœ… Stripe keys in environment (never in code) ## ๐Ÿ“ž Support For issues, check: 1. API logs for webhook errors 2. Stripe Dashboard โ†’ Webhooks โ†’ Event logs 3. Supabase logs for database errors 4. Browser console for frontend errors --- **Files:** - Database: `sql/35_stripe_wrappers.sql` + `sql/36_fix_stripe_subscription_dates.sql` + `sql/37_secure_active_subscriptions.sql` - Backend: `api/src/stripe.ts` + `api/src/stripeSync.ts` - Frontend: `apps/main/src/hooks/stripe.ts` - Types: `packages/shared/src/types/stripe.types.ts` - Security: `docs/STRIPE_SECURITY_FIX.md`