Skip to main content

Stripe Integration Quick Start Guide

This guide helps you get the Stripe payment integration running locally in under 10 minutes.

Prerequisites

  • Node.js 18+ installed
  • pnpm package manager
  • PostgreSQL database running
  • Stripe account (free test mode)

Step 1: Install Dependencies (Already Done ✅)

The Stripe package has already been installed in the backend:

pnpm add stripe --filter backend

Step 2: Database Migration

Run the Prisma migration to add Stripe tables:

cd packages/database
pnpm prisma migrate deploy
# Or for development:
pnpm prisma migrate dev

Verify tables were created:

-- Check if new tables exist
SELECT table_name FROM information_schema.tables
WHERE table_name IN ('credit_pack_subscriptions', 'stripe_events');

Step 3: Get Stripe API Keys

1. Sign up for Stripe (if you haven't)

Visit: https://dashboard.stripe.com/register

2. Get Your Test Mode Keys

  1. Go to: https://dashboard.stripe.com/test/apikeys
  2. Copy your keys:
    • Publishable key: pk_test_...
    • Secret key: Click "Reveal test key" → sk_test_...

3. Set Up Webhook Locally

For local development, you have two options:

  1. Install Stripe CLI:
# macOS
brew install stripe/stripe-cli/stripe

# Windows (Scoop)
scoop bucket add stripe https://github.com/stripe/scoop-stripe-cli.git
scoop install stripe

# Linux
# Download from: https://github.com/stripe/stripe-cli/releases
  1. Login to Stripe:
stripe login
  1. Forward webhooks to your local server:
stripe listen --forward-to localhost:3800/stripe/webhook
  1. Copy the webhook signing secret that appears (starts with whsec_...)

Option B: Use Cloudflare Tunnel (For Public URL)

If your backend is already exposed via Cloudflare Tunnel:

  1. Go to: https://dashboard.stripe.com/test/webhooks
  2. Click Add endpoint
  3. Enter URL: https://api-dev.civstart.ventures/stripe/webhook
  4. Select events (see STRIPE_PRODUCT_SETUP.md)
  5. Copy the signing secret

Step 4: Configure Environment Variables

Add these to your .env file in the project root:

# Stripe Configuration (Test Mode)
STRIPE_SECRET_KEY=sk_test_YOUR_SECRET_KEY_HERE
STRIPE_PUBLISHABLE_KEY=pk_test_YOUR_PUBLISHABLE_KEY_HERE
STRIPE_WEBHOOK_SECRET=whsec_YOUR_WEBHOOK_SECRET_HERE
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_YOUR_PUBLISHABLE_KEY_HERE

Note: Replace the placeholder values with your actual keys from Step 3.


Step 5: Set Up Test Products in Stripe

Follow the detailed guide in STRIPE_PRODUCT_SETUP.md, or use this quick setup:

Quick Test Product Setup

  1. Go to: https://dashboard.stripe.com/test/products

  2. Click Add product

  3. Create GovFit Platform Access:

    • Name: GovFit Platform Access
    • Price: $12,000 USD, Recurring yearly, billed monthly
    • Lookup key: govfit_platform_access
    • Metadata: credits=1, frequency=monthly, productType=govfit
  4. Create 4-Credit Pack (for testing):

    • Name: 4-Credit Pack
    • Add two prices:
      • One-time: $2,000, lookup: creditpack_4_onetime
      • Monthly: $1,800, lookup: creditpack_4_monthly
    • Metadata: credits=4, productType=creditpack, rolloverLimit=10

Step 6: Start the Backend

# From project root
pnpm dev

# Or just the backend
cd apps/backend
pnpm dev

The backend should start on http://localhost:3800


Step 7: Test the Integration

1. Health Check

Test that the Stripe module is loaded:

curl http://localhost:3800/stripe/health

Expected response:

{
"status": "ok",
"timestamp": "2024-12-02T..."
}

2. Create a Test Checkout Session

You'll need a valid Clerk JWT token. Get it from your frontend or use Clerk's test tokens.

curl -X POST http://localhost:3800/stripe/create-checkout-session \
-H "Authorization: Bearer YOUR_CLERK_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"priceId": "price_YOUR_PRICE_ID",
"successUrl": "http://localhost:3801/success",
"cancelUrl": "http://localhost:3801/cancel"
}'

Expected response:

{
"checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_...",
"sessionId": "cs_test_..."
}

3. Complete a Test Purchase

  1. Open the checkoutUrl in your browser
  2. Use Stripe test card: 4242 4242 4242 4242
  3. Fill in any future expiry, any CVC, any ZIP
  4. Complete the purchase

4. Verify Webhook Received

Check your backend logs for:

[StripeWebhookController] Received Stripe event: checkout.session.completed
[StripeService] Successfully processed checkout for startup ...

Check database:

-- Verify event was logged
SELECT * FROM stripe_events ORDER BY created_at DESC LIMIT 1;

-- Check if credits were added
SELECT credits_remaining, monthly_allocation
FROM startup_contacts
WHERE contact_email = 'your-test-email@example.com';

Step 8: Test Subscription Management

Get Active Subscriptions

curl http://localhost:3800/stripe/subscriptions \
-H "Authorization: Bearer YOUR_CLERK_JWT_TOKEN"

Get Billing History

curl http://localhost:3800/stripe/billing-history \
-H "Authorization: Bearer YOUR_CLERK_JWT_TOKEN"

Cancel a Subscription

curl -X POST http://localhost:3800/stripe/cancel-subscription \
-H "Authorization: Bearer YOUR_CLERK_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subscriptionId": "sub_xxx"
}'

Common Issues & Solutions

Issue: "STRIPE_SECRET_KEY is not configured"

Solution: Verify your .env file has the correct Stripe keys and restart the backend.

Issue: "Webhook signature verification failed"

Solutions:

  1. Verify STRIPE_WEBHOOK_SECRET is correct
  2. If using Stripe CLI, make sure it's running: stripe listen --forward-to localhost:3800/stripe/webhook
  3. If using dashboard webhook, verify endpoint URL is publicly accessible

Issue: "Startup not found for this user"

Solution: Ensure your test user email exists in the startup_contacts table:

INSERT INTO startup_contacts (id, airtable_record_id, startup_name, contact_email)
VALUES ('test-startup-id', 'rec_test', 'Test Startup', 'your-email@example.com');

Issue: Credits not added after purchase

Solutions:

  1. Check webhook was received (look for checkout.session.completed in logs)
  2. Verify metadata is correct on the Stripe price
  3. Check stripe_events table for processing errors:
    SELECT * FROM stripe_events WHERE processing_error IS NOT NULL;

Issue: "PrismaService not found"

Solution: The Stripe module depends on core services. Verify app.module.ts imports StripeModule AFTER ConfigModule.


Testing Scenarios

Scenario 1: GovFit Subscription

  1. Create checkout session for govfit_platform_access
  2. Complete purchase with test card
  3. Verify:
    • govfitSubscriptionId is set
    • govfitSubscriptionStatus = 'active'
    • monthlyAllocation = 1
    • creditsRemaining increased by 1

Scenario 2: One-Time Credit Pack

  1. Create checkout for creditpack_4_onetime
  2. Complete purchase
  3. Verify:
    • creditsRemaining increased by 4
    • No subscription created
    • Transaction logged with type 'stripe_purchase'

Scenario 3: Monthly Credit Pack

  1. Create checkout for creditpack_4_monthly
  2. Complete purchase
  3. Verify:
    • Entry in credit_pack_subscriptions table
    • creditsRemaining increased by 4
    • monthlyAllocation increased by 4
    • rolloverLimit = 10

Scenario 4: Credit Rollover (Requires Time Simulation)

  1. Subscribe to monthly credit pack
  2. Use only 2 credits (leave 2 unused)
  3. Trigger renewal (simulate invoice.paid event)
  4. Verify:
    • New total = 4 (monthly) + 2 (rollover) = 6 credits
    • Rollover respects limit (max 10 for 4-credit pack)

Scenario 5: Subscription Cancellation

  1. Cancel subscription via API or Stripe dashboard
  2. Verify:
    • govfitSubscriptionStatus = 'canceled'
    • subscriptionGracePeriodEnd set to +1 day
    • Can still access during grace period

Development Workflow

1. Make Changes to Stripe Logic

Edit files in apps/backend/src/stripe/

2. Restart Backend

The backend will auto-reload with pnpm dev

3. Test Changes

Use curl commands or Postman to test endpoints

4. Check Logs

Monitor terminal for logs from StripeService and StripeWebhookController

5. Verify Database Changes

-- Check recent transactions
SELECT * FROM credit_transactions
ORDER BY created_at DESC LIMIT 10;

-- Check webhook events
SELECT type, processed, processing_error
FROM stripe_events
ORDER BY created_at DESC LIMIT 10;

-- Check subscriptions
SELECT sc.startup_name, sc.govfit_subscription_status, cps.credits, cps.status
FROM startup_contacts sc
LEFT JOIN credit_pack_subscriptions cps ON sc.id = cps.startup_id;

Next Steps

  1. Frontend Integration - Implement billing UI (see Phase 2 in STRIPE_IMPLEMENTATION_SUMMARY.md)
  2. Email Notifications - Set up email templates for:
    • Purchase confirmations
    • Subscription renewals
    • Payment failures
    • Expiry warnings
  3. Admin Dashboard - Add admin tools for:
    • Viewing all subscriptions
    • Manually triggering renewals
    • Refunding purchases
  4. Testing - Write unit and integration tests
  5. Production Deployment - Switch to live mode (see STRIPE_PRODUCT_SETUP.md)

Useful Commands

Stripe CLI Commands

# Listen for webhooks
stripe listen --forward-to localhost:3800/stripe/webhook

# Trigger specific webhook event
stripe trigger checkout.session.completed

# View recent events
stripe events list --limit 10

# Get subscription details
stripe subscriptions retrieve sub_xxx

Database Queries

# Connect to database
psql $DATABASE_URL

# Check Stripe customers
SELECT id, startup_name, stripe_customer_id, govfit_subscription_status
FROM startup_contacts
WHERE stripe_customer_id IS NOT NULL;

# Check recent credit changes
SELECT sc.startup_name, ct.action_type, ct.amount, ct.created_at
FROM credit_transactions ct
JOIN startup_contacts sc ON ct.startup_id = sc.id
ORDER BY ct.created_at DESC
LIMIT 20;

Support

  • Stripe Issues: Check Stripe Documentation
  • Backend Issues: Review STRIPE_IMPLEMENTATION_SUMMARY.md
  • Setup Issues: Follow STRIPE_PRODUCT_SETUP.md

Happy Testing! 🚀