Production-Grade Payment Integration

Stripe Payment
Lifecycle

Explicit state machine. Webhook-driven truth. Zero card data storage.

Next.js
TypeScript
Stripe
Supabase
Node.js
Tailwind CSS
Free tier API may take up to 50s to wake up

Technical Architecture

Production-grade payment system with explicit state management and webhook-driven truth

System Architecture

BrowserNext.jsExpress APIStripeSupabasewebhook

Payment State Machine

Created

Payment intent created. Awaiting customer action to provide payment details.

Note: Only webhooks can transition to terminal states (succeeded/failed). Frontend never confirms payment success.

Technology Stack

Frontend

Modern React with server components

Next.js 14React 18TypeScriptTailwind CSS

Backend API

Node.js REST API with TypeScript

ExpressNode.jsTypeScriptZod Validation

Database

Managed PostgreSQL with ACID guarantees

PostgreSQLSupabaseDrizzle ORM

Payments

Stripe Payment Intents API

Stripe SDKPayment ElementsWebhooks

Security

PCI-compliant, zero card storage

HelmetRate LimitingHTTPSCSP

DevOps

Containerized deployment

DockerGitHub Actionspnpm Monorepo

Key Features

Production-grade patterns for reliable payment processing

Reliable

Webhook-Driven Truth

Database is the source of truth, updated only by verified Stripe webhooks

  • Signature verification on all webhook events
  • Idempotent event processing
  • Only webhooks can confirm payment success/failure
  • Frontend polls for status updates
Safe

Idempotency First

All payment operations are safe to retry without duplicate charges

  • Idempotency keys on all Stripe API calls
  • Database constraints prevent duplicates
  • Webhook deduplication via event IDs
  • Safe retry mechanisms built-in
Secure

PCI Compliance (SAQ A)

Zero card data touches your servers - lowest compliance burden

  • Stripe.js handles all card data
  • No PCI DSS Level 1 requirements
  • Sensitive data redacted from logs
  • Security headers and rate limiting
Predictable

Explicit State Machine

Payment states follow a strict, auditable state machine

  • Five well-defined states
  • Only valid transitions allowed
  • All transitions logged and timestamped
  • No implicit state changes

Production-ready architecture — Every design decision optimized for reliability, security, and maintainability

Payment Flow

See how a payment travels through the system with webhook-driven confirmation

1

Create Payment

Customer clicks "Pay Now" - frontend calls API to create PaymentIntent

2

Enter Card Details

Stripe.js securely collects card data - never touches your servers

3

Confirm Payment

Customer confirms - Stripe processes payment and handles 3DS if needed

4

Webhook Received

Stripe sends verified webhook event with payment outcome

5

State Updated

Webhook handler updates database state to succeeded or failed

6

Success Confirmed

Frontend polls database and displays final payment status

Why Webhook-Driven?

The frontend never confirms payment success based on client-side responses. Only verified webhook events from Stripe can update the payment state to succeeded or failed. This ensures payments are never missed or double-counted, even if the customer closes their browser mid-transaction.

Ready to see it in action?

Try the live demo with Stripe test cards or explore the complete source code

Free tier API may take up to 50s to wake up

Test Cards for Demo

Success4242 4242 4242 4242
3DS Required4000 0025 0000 3155
Declined4000 0000 0000 0002

Use any future expiry date and any 3-digit CVC

Built with Next.js, TypeScript, Stripe, and Supabase