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

264 lines
7.4 KiB
Markdown

# 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