Skip to content

taiseen/stripe-nextjs-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

6 - September - 2025

Stripe Payment System

🧐 Some Features:-

  • βš›οΈ Tech Stack: Next.js 14, TypeScript, Prisma, MongoDB, Stripe
  • πŸ” User Authentication with Kinde Auth
  • πŸ’Έ Monthly & Annually Subscriptions with Stripe
  • πŸ’΅ Building a Stripe Billing Portal
  • πŸͺ Subscriptions Webhooks
  • πŸ”„ Stripe Event Types
  • πŸŒ— Light/Dark Mode
  • 🌐 Deployment

βš™οΈ Setup .env file

DATABASE_URL= get_your_mongo_db_url

KINDE_CLIENT_SECRET = 
KINDE_CLIENT_ID = 
KINDE_ISSUER_URL = 
KINDE_SITE_URL = 
KINDE_POST_LOGOUT_REDIRECT_URL = 
KINDE_POST_LOGIN_REDIRECT_URL = 

STRIPE_MONTHLY_PLAN_LINK = get_from_stripe
STRIPE_YEARLY_PLAN_LINK = get_from_stripe

STRIPE_MONTHLY_PRICE_ID = get_from_stripe
STRIPE_YEARLY_PRICE_ID = get_from_stripe

STRIPE_SECRET_KEY = get_from_stripe
STRIPE_WEBHOOK_SECRET = get_from_stripe

NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL_URL = get_from_stripe

Install dependencies

npm install

Start the app

npm run dev

🧠 Learning context:-

  • File & Folder Structure
  • Stripe product setup
    • create product link + id
      • same product 2 version for monthly & yearly
    • webhook - local running for testing
      • yarn add stripe
      • download & install stripe cli & PATH configure
      • stripe login
      • stripe listen --forward-to localhost:3000/api/webhooks/stripe

πŸ› οΈ This project falls under

- System Design 
- API Integration 
- State Management
- Integration Engineering
- Practical Software Engineering

🎨 UI Packages

  • npx shadcn@latest add dropdown-menu
  • npx shadcn@latest add navigation-menu
  • npx shadcn@latest add badge
  • npx shadcn@latest add card

πŸ›’οΈ Database

  • prisma + mongodb
  • npx prisma init
  • npx prisma db push

πŸ›‘οΈ Auth & Payment System

STRIPE WEBHOOK β€” STEPS & FUNCTION DEPENDENCY GRAPH

  • πŸ—οΈ Architecture with 🧠 clarity
🌐 1. ENTRY POINT               β€” POST /api/webhooks
πŸ” 2. VERIFY SIGNATURE          β€” verify_Stripe_Webhook_Signature(...)
🧭 3. ROUTE EVENT               β€” handle_Webhook_Event_Route(...)
πŸ›’ 4. HANDLE CHECKOUT COMPLETED β€” handle_Checkout_Session_Completed(...)
πŸ‘€ 5. SYNC USER                 β€” sync_User_With_Stripe_Customer_Id(...)
πŸ“… 6. UPDATE SUBSCRIPTION       β€” update_Subscription_Info_For_User(...)
Verify β†’ Route β†’ Sync β†’ Update β†’ Plan

[Stripe POST]
    ↓
[Verify Signature] β†’ Trust βœ…
    ↓
[Route by Event Type] β†’ checkout.session.completed
    ↓
[Retrieve Session + Line Items]
    ↓
[Find User by Email] β†’ Sync/Link customerId
    ↓
[For Each Item] β†’ Is Subscription?
        ↓ [Yes] β†’ Update Subscription + Upgrade User Plan
        ↓ [No]  β†’ Skip (One-time)
    ↓
[Return 200] β†’ Done βœ…
πŸšͺ Layer 1: Entry & Verification
route.ts
└── verifyStripeWebhookSignature

🧭 Layer 2: Routing & Event Handling
handleStripeWebhookEventRoute
└── handleCheckoutSessionCompleted

πŸ§‘ Layer 3: User Sync
handleCheckoutSessionCompleted
└── syncUserWithStripeCustomerId
    └── Prisma (find + update)
    
πŸ“¦ Layer 4: Subscription & Plan Activation    
handleCheckoutSessionCompleted
└── updateSubscriptionInfoForUser
    β”œβ”€β”€ getPlanDetails
    └── Prisma (upsert subscription + update user plan)
POST /api/webhooks (route.ts)
       β”‚
       β–Ό
verifyStripeWebhookSignature(payload, signature, secret) β†’ returns Stripe.Event
       β”‚
       β–Ό
handleStripeWebhookEventRoute(event) β†’ routes by event.type
       β”‚
       β–Ό
handleCheckoutSessionCompleted(session) β†’ main logic for payment success
       β”‚
       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Ί syncUserWithStripeCustomerId(email, customerId) β†’ returns User
       β”‚                         β”‚
       β”‚                         β–Ό
       β”‚                  prisma.user.findUnique + .update
       β”‚
       β–Ό
FOR EACH line_item β†’ if subscription β†’ updateSubscriptionInfoForUser(userId, priceId)
                                 β”‚
                                 β–Ό
                         getPlanDetails(priceId) β†’ returns { period, endDate }
                                 β”‚
                                 β–Ό
                         prisma.subscription.upsert
                                 β”‚
                                 β–Ό
                         prisma.user.update β†’ set plan = "premium"

STRIPE EVENT LOG

  • ⏰ All events happened within ~15 seconds β€” typical for a successful subscription checkout.
  • Stripe sends 20+ events for one checkout β€” we only need 1–2 to start.
  • Stripe sends one webhook event per system action &
    • a subscription checkout triggers many actions - almost 7+
  • WEBHOOK - ENDPOINT
2025-09-20 20:21:00   --> charge.succeeded [evt_3SuX]               β†’ πŸ’° Money captured!
2025-09-20 20:21:00   --> payment_method.attached [evt_1Sgb]
2025-09-20 20:21:00   --> customer.created [evt_1SX3]
2025-09-20 20:21:00   --> customer.updated [evt_1Shv]
2025-09-20 20:21:00   --> checkout.session.completed [evt_1SiA]     β†’ 🎯 THIS IS OUR WORKING EVENT AREA
2025-09-20 20:21:00   --> customer.subscription.created [evt_1S8k]
2025-09-20 20:21:00  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1Sgb]
2025-09-20 20:21:00  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_3SuX]
2025-09-20 20:21:00  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SX3]
2025-09-20 20:21:00  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1S8k]
2025-09-20 20:21:00  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1Shv]
2025-09-20 20:21:01   --> payment_intent.created [evt_3S9o]
2025-09-20 20:21:01   --> payment_intent.succeeded [evt_3SIm]       β†’ βœ… Payment authorized & succeeded
2025-09-20 20:21:01  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_3S9o]
2025-09-20 20:21:01  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_3SIm]
2025-09-20 20:21:01   --> invoice.created [evt_1Sm8]
2025-09-20 20:21:01   --> invoice.finalized [evt_1SOF]
2025-09-20 20:21:01  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1Sm8]
2025-09-20 20:21:01  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SOF]
2025-09-20 20:21:01   --> invoice.paid [evt_1SQa]
2025-09-20 20:21:01   --> invoice.payment_succeeded [evt_1Swm]
2025-09-20 20:21:01  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SQa]
2025-09-20 20:21:01  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1Swm]
2025-09-20 20:21:08  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SiA]
2025-09-20 20:21:15   --> invoice_payment.paid [evt_1SEa]
2025-09-20 20:21:15  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SEa]

2025-09-21 03:56:05   --> billing_portal.configuration.created [evt_1SJL]
2025-09-21 03:56:05   --> billing_portal.configuration.updated [evt_1SwW]
2025-09-21 03:56:08  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SwW]
2025-09-21 03:56:08  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SJL]
2025-09-21 03:58:43   --> billing_portal.configuration.updated [evt_1SQW]
2025-09-21 03:58:44  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SQW]
2025-09-21 04:03:22   --> billing_portal.session.created [evt_1SSt]
2025-09-21 04:03:24  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SSt]
2025-09-21 04:08:46   --> setup_intent.created [evt_1SIf]
2025-09-21 04:08:46  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SIf]

2025-09-21 04:15:17   --> customer.subscription.updated [evt_1SeJ]
2025-09-21 04:15:17  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SeJ]

2025-09-21 04:18:12   --> customer.subscription.deleted [evt_1SoF]  β†’ 🎯 THIS IS OUR WORKING EVENT AREA
2025-09-21 04:18:17  <--  [200] POST [WEBHOOK - ENDPOINT] [evt_1SoF]