# TenderRadar Stripe Payment Integration This document describes the Stripe payment integration for TenderRadar, including setup instructions and API endpoints. ## Overview TenderRadar now supports three paid subscription tiers via Stripe: - **Starter**: £39/month - **Growth**: £99/month - **Pro**: £249/month All plans include a 14-day free trial. ## Database Schema A new `subscriptions` table has been added to track user subscription status: ```sql CREATE TABLE subscriptions ( id SERIAL PRIMARY KEY, user_id INTEGER UNIQUE REFERENCES users(id) ON DELETE CASCADE, stripe_customer_id VARCHAR(255) UNIQUE NOT NULL, stripe_subscription_id VARCHAR(255), plan VARCHAR(50) NOT NULL, status VARCHAR(50) NOT NULL DEFAULT 'active', trial_start TIMESTAMP, trial_end TIMESTAMP, current_period_start TIMESTAMP, current_period_end TIMESTAMP, cancel_at_period_end BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` **Fields:** - `user_id`: Reference to the user account - `stripe_customer_id`: Stripe customer ID for this user - `stripe_subscription_id`: Active Stripe subscription ID - `plan`: Current plan tier (starter, growth, pro) - `status`: Subscription status (active, trialing, past_due, cancelled) - `trial_start/end`: Trial period dates - `current_period_start/end`: Current billing period dates - `cancel_at_period_end`: Whether subscription is scheduled for cancellation ## Environment Variables Add the following to `.env`: ```env # Stripe API Keys (from Stripe Dashboard) STRIPE_SECRET_KEY=sk_test_placeholder STRIPE_PUBLISHABLE_KEY=pk_test_placeholder STRIPE_WEBHOOK_SECRET=whsec_placeholder # Stripe Price IDs (created in Stripe Dashboard) STRIPE_PRICE_STARTER=price_starter_placeholder STRIPE_PRICE_GROWTH=price_growth_placeholder STRIPE_PRICE_PRO=price_pro_placeholder ``` **Peter: Update these placeholder values with your actual Stripe keys.** ## Setup Instructions ### 1. Create Stripe Account and Get API Keys 1. Sign up at https://dashboard.stripe.com 2. Navigate to Developers → API Keys 3. Copy your **Secret Key** (starts with `sk_test_` or `sk_live_`) 4. Copy your **Publishable Key** (starts with `pk_test_` or `pk_live_`) 5. Update `.env` with these keys ### 2. Create Webhook Endpoint 1. In Stripe Dashboard, go to Developers → Webhooks 2. Click "Add an endpoint" 3. Endpoint URL: `https://your-domain.com/api/billing/webhook` 4. Select events to listen for: - `checkout.session.completed` - `customer.subscription.updated` - `customer.subscription.deleted` - `invoice.payment_failed` 5. Copy the **Signing Secret** (starts with `whsec_`) 6. Update `.env` with `STRIPE_WEBHOOK_SECRET` ### 3. Create Stripe Price Objects In Stripe Dashboard, go to Products → Create Product: #### Starter Plan - Name: "TenderRadar Starter" - Price: £39.00 GBP / month - Recurring: Monthly - Copy the Price ID (starts with `price_`) → `STRIPE_PRICE_STARTER` #### Growth Plan - Name: "TenderRadar Growth" - Price: £99.00 GBP / month - Recurring: Monthly - Copy the Price ID → `STRIPE_PRICE_GROWTH` #### Pro Plan - Name: "TenderRadar Pro" - Price: £249.00 GBP / month - Recurring: Monthly - Copy the Price ID → `STRIPE_PRICE_PRO` Update `.env` with all three Price IDs. ### 4. Initialize Database If this is a fresh setup, run: ```bash node init-db.js ``` This will create the `subscriptions` table and indexes. ### 5. Restart Server ```bash npm start ``` ## API Endpoints ### POST /api/billing/checkout Creates a Stripe Checkout session for a selected plan. **Request:** ```json { "plan": "starter|growth|pro", "successUrl": "https://app.example.com/success", "cancelUrl": "https://app.example.com/cancel" } ``` **Response:** ```json { "sessionId": "cs_test_...", "url": "https://checkout.stripe.com/pay/..." } ``` **Usage:** 1. Call this endpoint with the desired plan 2. Redirect user to the returned `url` 3. User completes payment on Stripe Checkout 4. Stripe redirects to `successUrl` ### POST /api/billing/webhook Handles incoming Stripe webhook events. This endpoint is automatically called by Stripe. **Handled Events:** - `checkout.session.completed` - Creates subscription record when user completes checkout - `customer.subscription.updated` - Updates subscription status in database - `customer.subscription.deleted` - Marks subscription as cancelled - `invoice.payment_failed` - Logs failed payment (can trigger alerts) ### GET /api/billing/subscription Retrieves the current subscription status for the authenticated user. **Response (with active subscription):** ```json { "subscription": { "id": 1, "user_id": 42, "stripe_customer_id": "cus_...", "stripe_subscription_id": "sub_...", "plan": "growth", "status": "active", "trial_start": "2026-02-14T12:00:00Z", "trial_end": "2026-02-28T12:00:00Z", "current_period_start": "2026-03-14T12:00:00Z", "current_period_end": "2026-04-14T12:00:00Z", "cancel_at_period_end": false, "created_at": "2026-02-14T12:00:00Z", "updated_at": "2026-02-14T12:00:00Z" } } ``` **Response (no subscription):** ```json { "subscription": null, "message": "No active subscription. User is on free tier." } ``` ### POST /api/billing/portal Creates a Stripe Customer Portal session for managing subscriptions (upgrade, downgrade, cancel). **Request:** ```json { "returnUrl": "https://app.example.com/billing" } ``` **Response:** ```json { "url": "https://billing.stripe.com/session/..." } ``` ## Middleware ### attachSubscription(pool) Automatically attaches subscription info to `req.subscription` for all authenticated requests. Place after `verifyToken` middleware. ### requireActiveSubscription Middleware to restrict endpoints to users with active subscriptions. Use for premium features: ```javascript app.get('/api/premium-feature', verifyToken, requireActiveSubscription, (req, res) => { // This endpoint now requires active subscription }); ``` ## Implementation Notes - **Stripe Checkout** is used for PCI compliance (no sensitive payment data handled by TenderRadar) - **14-day trial** is automatically applied to all subscriptions via checkout session config - **Webhook validation** ensures events are authentic before processing - **Subscription metadata** includes `user_id` and `plan` for easy lookup - **Raw body parsing** is configured for the webhook endpoint to verify signatures - **Plan mapping** converts plan names to Stripe Price IDs in `stripe-billing.js` ## Testing Webhook Locally For local development, use Stripe CLI: ```bash # Install Stripe CLI: https://stripe.com/docs/stripe-cli stripe login stripe listen --forward-to localhost:3456/api/billing/webhook ``` This outputs a webhook signing secret — update `.env` with this value for testing. ## File Structure ``` ├── server.js # Main Express app with billing routes ├── stripe-billing.js # Stripe integration functions ├── subscription-middleware.js # Middleware for subscription checks ├── init-db.js # Database setup (includes subscriptions table) ├── .env # Configuration (update with Stripe keys) └── STRIPE_SETUP.md # This file ``` ## Support For questions about Stripe integration, consult: - Stripe API Docs: https://stripe.com/docs/api - Stripe Webhooks: https://stripe.com/docs/webhooks - Stripe Checkout: https://stripe.com/docs/payments/checkout