Skip to content

feat: Stripe Checkout integration with 7-day free trial for all subscription tiers#83

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/integrate-stripe-checkout
Draft

feat: Stripe Checkout integration with 7-day free trial for all subscription tiers#83
Copilot wants to merge 3 commits intomainfrom
copilot/integrate-stripe-checkout

Conversation

Copy link

Copilot AI commented Mar 12, 2026

Wires up Stripe Checkout for the three subscription tiers (Single €9.99, Triple €19.99, All Access €29.99), each with a 7-day free trial. Covers the full subscription lifecycle via webhooks.

Backend

  • stripe.tscreate-checkout-session now accepts { priceId } and maps to plan name via hardcoded lookup; session uses trial_period_days: 7, success/cancel URLs use FRONTEND_URL with production fallback:

    const PRICE_PLAN_MAP: Record<string, string> = {
      price_1TAAKQPfPehc9iSUDPPWTaqb: 'single',
      price_1TAALHPfPehc9iSUuHHj00NO: 'triple',
      price_1TAAM8PfPehc9iSU9mJxnfDQ: 'all_access',
    };
  • Webhook handlers updated/added:

    Event DB change
    checkout.session.completed subscription_status = 'trialing', sets trial_ends_at, stripe_subscription_id
    customer.subscription.updated mirrors Stripe subscription.status
    customer.subscription.deleted plan = 'free', subscription_status = 'cancelled'
    invoice.payment_failed subscription_status = 'past_due'
  • migrations/004_add_stripe_fields.sqlIF NOT EXISTS migration for stripe_customer_id, stripe_subscription_id, trial_ends_at (safe against existing schema from 001)

  • .env.example — adds STRIPE_PUBLISHABLE_KEY, locks in the three live EUR price IDs

Frontend

  • pages/api/create-checkout-session.ts — Next.js API proxy forwarding to backend with Authorization header passthrough
  • pages/landing.tsx — "Start Free Trial" pricing card buttons wired to handleSubscribe(priceId); unauthenticated users redirected to /signup; per-button loading state; error display below pricing grid
  • pages/dashboard.tsx — shows dismissible success banner (🎉 Welcome! Your 7-day free trial has started.) when ?subscription=success is present; URL cleaned via shallow routing
  • pages/checkout.tsx — updated to send { priceId, sports } using a PLAN_PRICE_IDS map instead of { plan, sports }
Original prompt

Stripe Checkout Integration — 7-Day Free Trial

Integrate Stripe Checkout into the AI Sports Almanac app to handle paid subscriptions for the three pricing tiers, each with a 7-day free trial.

Stripe Price IDs (live, EUR)

Plan Price ID Price
Single agent price_1TAAKQPfPehc9iSUDPPWTaqb €9.99/month
Triple tier price_1TAALHPfPehc9iSUuHHj00NO €19.99/month
All Access price_1TAAM8PfPehc9iSU9mJxnfDQ €29.99/month

What needs to be implemented

1. Backend — AI-Sports-Almanac/backend/

Install Stripe:
Add stripe to package.json dependencies.

New file: AI-Sports-Almanac/backend/src/api/routes/stripe.ts

Create a new Express router with the following endpoints:

  • POST /api/stripe/create-checkout-session (authenticated)

    • Accepts { priceId: string } in request body
    • Maps price ID to plan name:
      • price_1TAAKQPfPehc9iSUDPPWTaqbsingle
      • price_1TAALHPfPehc9iSUuHHj00NOtriple
      • price_1TAAM8PfPehc9iSU9mJxnfDQall_access
    • Creates a Stripe Checkout Session with:
      • mode: 'subscription'
      • subscription_data: { trial_period_days: 7 }
      • success_url: 'https://aisportsalmanac.io/dashboard?subscription=success'
      • cancel_url: 'https://aisportsalmanac.io/pricing'
      • customer_email: set to the authenticated user's email
      • metadata: { userId: req.user.id, plan: planName }
    • Returns { url: session.url }
  • POST /api/stripe/webhook (public, no auth, raw body)

    • Verifies Stripe webhook signature using STRIPE_WEBHOOK_SECRET env var
    • Handles the following events:
      • checkout.session.completed → update user's plan in DB to the plan from metadata, set subscription_status = 'trialing', store stripe_customer_id and stripe_subscription_id
      • customer.subscription.updated → update subscription_status based on subscription.status
      • customer.subscription.deleted → set user plan to free, set subscription_status = 'cancelled'
      • invoice.payment_failed → set subscription_status = 'past_due'
    • Uses pool from ../../utils/db to update the users table
    • Uses logger from ../../utils/logger

Update AI-Sports-Almanac/backend/src/index.ts:

  • Add raw body parsing for /api/stripe/webhook route BEFORE the json body parser (this is critical for webhook signature verification)
  • Register the stripe router: app.use('/api/stripe', stripeRouter)
  • Import the stripe router

Update AI-Sports-Almanac/backend/src/api/routes/admin.ts:

  • No changes needed here

Update .env.example at AI-Sports-Almanac/backend/.env.example:
Add:

STRIPE_SECRET_KEY=sk_live_...
STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE_SINGLE=price_1TAAKQPfPehc9iSUDPPWTaqb
STRIPE_PRICE_TRIPLE=price_1TAALHPfPehc9iSUuHHj00NO
STRIPE_PRICE_ALL_ACCESS=price_1TAAM8PfPehc9iSU9mJxnfDQ

New migration file: AI-Sports-Almanac/backend/migrations/004_add_stripe_fields.sql

ALTER TABLE users 
  ADD COLUMN IF NOT EXISTS stripe_customer_id VARCHAR(255),
  ADD COLUMN IF NOT EXISTS stripe_subscription_id VARCHAR(255),
  ADD COLUMN IF NOT EXISTS trial_ends_at TIMESTAMP WITH TIME ZONE;

2. Frontend — AI-Sports-Almanac/frontend/

New file: AI-Sports-Almanac/frontend/pages/api/create-checkout-session.ts (Next.js API proxy)

  • Proxies the request to the backend /api/stripe/create-checkout-session
  • Passes the Authorization header through

Update the pricing page / "Start Free Trial" buttons:
Look in AI-Sports-Almanac/frontend/pages/ and AI-Sports-Almanac/frontend/components/ for the pricing page (likely pricing.tsx or similar, or a Pricing component).

Add a handleSubscribe function that:

  1. Gets the JWT token from localStorage (token key)
  2. POSTs to /api/stripe/create-checkout-session with the appropriate priceId
  3. Redirects to the returned url (Stripe Checkout page)
  4. Shows a loading state on the button while processing
  5. Shows an error toast/alert if it fails

Map the buttons to the correct price IDs:

  • Singleprice_1TAAKQPfPehc9iSUDPPWTaqb
  • Tripleprice_1TAALHPfPehc9iSUuHHj00NO
  • All Accessprice_1TAAM8PfPehc9iSU9mJxnfDQ

New file: AI-Sports-Almanac/frontend/pages/dashboard/subscription-success.tsx OR handle in the dashboard page:

  • When ?subscription=success query param is present on the dashboard, show a success banner: "🎉 Welcome! Your 7-day free trial has started. Enjoy full access!"

3. Root .env.example update

Update AI-Sports-Almanac/.env.example to include the Stripe environment variables.

Important notes

  • The webhook endpoint MUST use express.raw({ type: 'application/json' }) middleware, NOT express.json(), for Stripe signature verification to work
  • Use process.env.STRIPE_SECRET_KEY for the Stripe client initialisation
  • Use process.env.STRIPE_WEBHOOK_SECRET for webhook verification
  • The plan names...

This pull request was created from Copilot chat.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits March 12, 2026 15:03
Co-authored-by: Bitpass-dev <186615221+Bitpass-dev@users.noreply.github.com>
…eEffect dep, simplify nullish coalescing

Co-authored-by: Bitpass-dev <186615221+Bitpass-dev@users.noreply.github.com>
Copilot AI changed the title [WIP] Integrate Stripe Checkout for subscription management feat: Stripe Checkout integration with 7-day free trial for all subscription tiers Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants