Files
tenderpilot/STRIPE_SETUP.md
Peter Foster f969ecae04 feat: visual polish, nav login link, pricing badge fix, cursor fix, button contrast
- Hero mockup: enhanced 3D perspective and shadow
- Testimonials: illustrated SVG avatars
- Growth pricing card: visual prominence (scale, gradient, badge)
- Most Popular badge: repositioned to avoid overlapping heading
- Nav: added Log In link next to Start Free Trial
- Fixed btn-primary text colour on anchor tags (white on blue)
- Fixed cursor: default on all non-interactive elements
- Disabled user-select on non-form content to prevent text caret
2026-02-14 14:17:15 +00:00

7.4 KiB

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:

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:

# 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:

node init-db.js

This will create the subscriptions table and indexes.

5. Restart Server

npm start

API Endpoints

POST /api/billing/checkout

Creates a Stripe Checkout session for a selected plan.

Request:

{
  "plan": "starter|growth|pro",
  "successUrl": "https://app.example.com/success",
  "cancelUrl": "https://app.example.com/cancel"
}

Response:

{
  "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):

{
  "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):

{
  "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:

{
  "returnUrl": "https://app.example.com/billing"
}

Response:

{
  "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:

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:

# 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: