Overview
Stripe payment integration in Plainform with checkout sessions, subscriptions, customer portal, and webhooks
Plainform uses Stripe for payment processing, providing secure checkout, subscription management, and webhook integration out of the box.
What is Stripe?
Stripe is a complete payment platform that handles:
- One-time payments and subscriptions
- Checkout sessions with hosted payment pages
- Webhook events for payment status updates
- Manual payment capture for order verification
- Automatic tax calculation
- Coupon and promotion codes
- Customer portal for subscription management
How Plainform Uses Stripe
Plainform integrates Stripe at three key points:
- Checkout Flow (
app/api/stripe/checkout/) - Creates checkout sessions for one-time prices and recurring subscription prices - Customer Portal (
app/api/stripe/portal/) - Sends logged-in customers to Stripe Billing Portal to manage subscriptions - Webhooks (
app/api/webhooks/stripe/) - Routes Stripe events to focused handlers for payments, subscriptions, products, and coupons - Product Display (
lib/stripe/) - Fetches products, prices, coupons, customers, and sessions for the UI
For detailed information about Stripe's payment processing, security features, and advanced capabilities, see the official Stripe documentation.
Key Features in Plainform
Checkout Sessions
Pre-configured checkout with:
- Hosted payment page (no PCI compliance needed)
- Automatic tax calculation
- Manual capture for order verification
- Success/cancel URL redirects
- Requires a signed-in Clerk user before checkout
- Creates or reuses a Stripe customer linked to the Clerk user
Manual Payment Capture
Plainform uses manual capture mode for one-time payments:
- Payment is authorized but not charged immediately
- Allows order verification before capturing funds
- Can cancel authorization if order is invalid
- Capture or cancel via Stripe Dashboard or API
Webhook Integration
Real-time payment event processing:
checkout.session.completed- Delegates to one-time or subscription checkout handlerscustomer.subscription.created- Subscription startedcustomer.subscription.updated- Subscription renewed, changed, or scheduled for cancellationcustomer.subscription.deleted- Subscription fully endedproduct.*andcoupon.*- Pricing and event cache revalidation- Cache revalidation for products and coupons
Product & Pricing Display
Dynamic pricing section:
- Fetches products from Stripe API
- Displays prices with currency formatting
- Shows active coupons and discounts
- Cached with Next.js revalidation tags
Subscription Support
Full subscription lifecycle:
- Create subscription plans in Stripe Dashboard
- Automatic recurring billing
- Customer portal for plan management
- Webhook events for subscription changes
- Local
Usertable stores Stripe customer and subscription state - Product metadata can drive app-specific plan keys and feature limits
Customer Portal
Logged-in users can manage billing from the user menu. The menu posts to
/api/stripe/portal, which creates a Stripe Billing Portal session for the
current user's stripeCustomerId. If the user has no Stripe customer yet, they
are redirected back to the pricing section.
Environment Variables
Required Stripe configuration in .env:
# Publishable key
STRIPE_PUBLISHABLE_KEY=pk_test_...
# Secret key (server-side only)
STRIPE_SECRET_KEY=sk_test_...
# Webhook secret (for signature verification)
STRIPE_WEBHOOK_SECRET=whsec_...Never expose STRIPE_SECRET_KEY or STRIPE_WEBHOOK_SECRET in client-side
code. These are server-only secrets.
Payment Flow
One-Time Payment
User clicks "Buy Now"
↓
User must be signed in
↓
POST /api/stripe/checkout
↓
Create or reuse Stripe customer linked to Clerk user
↓
Stripe Checkout Session created (manual capture)
↓
User completes payment
↓
Webhook: checkout.session.completed
↓
Order saved to database (payment authorized)
↓
Manual review/verification
↓
Capture payment via Stripe Dashboard
↓
Checkout session metadata updated
↓
Confirmation email sentSubscription Payment
User selects subscription plan
↓
User must be signed in
↓
POST /api/stripe/checkout (mode: subscription)
↓
Create or reuse Stripe customer linked to Clerk user
↓
Stripe Checkout Session created
↓
User completes payment
↓
Webhook: customer.subscription.created
↓
Subscription saved to database
↓
Automatic recurring billing
↓
User manages plan in Stripe Billing PortalSecurity Features
- PCI Compliance - Stripe handles all payment data
- Webhook Signature Verification - Validates webhook authenticity
- Rate Limiting - Prevents checkout abuse (5 requests per 10 seconds)
- Manual Capture - Review orders before charging
- HTTPS Only - All API calls over secure connection
Performance Considerations
- Cached Product Data - Products fetched with
force-cacheand revalidation tags - Server-Side Only - Stripe client initialized with
'server-only'directive - Webhook Optimization - Fast event processing with targeted cache invalidation
- Minimal Client JS - Checkout redirects to Stripe-hosted page
Related Resources
Setup & Configuration
Configure Stripe API keys and webhook endpoints
Usage & Integration
Learn how to create checkouts and handle webhooks
Stripe Webhook
Understand event handlers, subscription sync, and extension points
Troubleshooting
Fix common payment integration issues
Stripe Documentation
Official Stripe documentation and API reference
How is this guide ?
Last updated on