A Stripe-like payment processing platform demonstrating payment APIs, financial ledger systems, and fraud prevention. This educational project focuses on building secure payment infrastructure with idempotency guarantees.
| Metric | Value |
|---|---|
| Total SLOC | 11,800 |
| Source Files | 61 |
| .js | 5,388 |
| .tsx | 2,193 |
| .md | 2,128 |
| .ts | 1,499 |
| .sql | 363 |
- Payment Intents API (create, confirm, capture, cancel)
- Customers and Payment Methods
- Refunds with ledger reconciliation
- Test card numbers for different scenarios
- Double-entry ledger system
- Processing fees (2.9% + 30c)
- Balance tracking and transactions
- Complete audit trail
- Signed webhook delivery
- Exponential backoff retry
- Event logging and replay
- Idempotency keys for safe retries
- API key authentication
- Fraud risk scoring
- Backend: Node.js + Express
- Frontend: TypeScript + Vite + React 19 + TanStack Router + Zustand + Tailwind CSS
- Database: PostgreSQL
- Cache/Queue: Redis + BullMQ
- Node.js 18+
- Docker and Docker Compose
-
Start infrastructure services:
cd stripe docker-compose up -d -
Install backend dependencies:
cd backend cp .env.example .env npm install -
Seed the database with demo data:
npm run db:seed
-
Start the backend server:
npm run dev
-
In a new terminal, install and start the frontend:
cd frontend npm install npm run dev -
Open your browser:
- Frontend Dashboard: http://localhost:5173
- API Documentation: http://localhost:3001/docs
If you prefer to run PostgreSQL and Redis natively:
-
PostgreSQL:
# macOS with Homebrew brew install postgresql@16 brew services start postgresql@16 createdb stripe_db psql -d stripe_db -f backend/src/db/init.sql -
Redis:
# macOS with Homebrew brew install redis brew services start redis -
Configure and run:
cd backend cp .env.example .env # Edit .env if using non-default credentials npm install npm run db:seed npm run dev
After seeding, use these credentials to log in:
- API Key:
sk_test_demo_merchant_key_12345
Or create a new merchant account in the UI.
| Card Number | Result |
|---|---|
| 4242 4242 4242 4242 | Success |
| 4000 0000 0000 0002 | Card declined |
| 4000 0000 0000 9995 | Insufficient funds |
| 4000 0000 0000 0069 | Expired card |
| 4000 0000 0000 0127 | Incorrect CVC |
| 4100 0000 0000 0019 | Fraud detected |
# Create a payment intent
curl -X POST http://localhost:3001/v1/payment_intents \
-H "Authorization: Bearer sk_test_demo_merchant_key_12345" \
-H "Content-Type: application/json" \
-d '{"amount": 2500, "currency": "usd"}'
# Confirm a payment intent
curl -X POST http://localhost:3001/v1/payment_intents/{id}/confirm \
-H "Authorization: Bearer sk_test_demo_merchant_key_12345" \
-H "Content-Type: application/json" \
-d '{"payment_method": "{pm_id}"}'
# List payment intents
curl http://localhost:3001/v1/payment_intents \
-H "Authorization: Bearer sk_test_demo_merchant_key_12345"# Create a payment method
curl -X POST http://localhost:3001/v1/payment_methods \
-H "Authorization: Bearer sk_test_demo_merchant_key_12345" \
-H "Content-Type: application/json" \
-d '{
"type": "card",
"card": {
"number": "4242424242424242",
"exp_month": 12,
"exp_year": 2027,
"cvc": "123"
}
}'# Create a customer
curl -X POST http://localhost:3001/v1/customers \
-H "Authorization: Bearer sk_test_demo_merchant_key_12345" \
-H "Content-Type: application/json" \
-d '{"email": "customer@example.com", "name": "Test Customer"}'# Create a refund
curl -X POST http://localhost:3001/v1/refunds \
-H "Authorization: Bearer sk_test_demo_merchant_key_12345" \
-H "Content-Type: application/json" \
-d '{"payment_intent": "{pi_id}"}'# Get balance
curl http://localhost:3001/v1/balance \
-H "Authorization: Bearer sk_test_demo_merchant_key_12345"
# Get balance summary
curl http://localhost:3001/v1/balance/summary \
-H "Authorization: Bearer sk_test_demo_merchant_key_12345"stripe/
├── docker-compose.yml # PostgreSQL and Redis
├── backend/
│ ├── src/
│ │ ├── index.js # Express app entry
│ │ ├── routes/ # API routes
│ │ │ ├── paymentIntents.js
│ │ │ ├── customers.js
│ │ │ ├── paymentMethods.js
│ │ │ ├── refunds.js
│ │ │ ├── charges.js
│ │ │ ├── balance.js
│ │ │ ├── webhooks.js
│ │ │ └── merchants.js
│ │ ├── services/ # Business logic
│ │ │ ├── ledger.js # Double-entry accounting
│ │ │ ├── fraud.js # Risk scoring
│ │ │ ├── webhooks.js # Webhook delivery
│ │ │ └── cardNetwork.js # Simulated card network
│ │ ├── middleware/ # Auth, idempotency
│ │ ├── db/ # Database connections
│ │ │ ├── init.sql # Schema
│ │ │ ├── pool.js # PostgreSQL
│ │ │ ├── redis.js # Redis
│ │ │ └── seed.js # Demo data
│ │ └── utils/ # Helpers
│ └── package.json
└── frontend/
├── src/
│ ├── routes/ # Pages
│ ├── components/ # UI components
│ ├── services/ # API client
│ ├── stores/ # Zustand state
│ ├── types/ # TypeScript types
│ └── utils/ # Helpers
└── package.json
All mutating endpoints support idempotency keys:
curl -X POST http://localhost:3001/v1/payment_intents \
-H "Idempotency-Key: unique-request-id" \
-H "Authorization: Bearer sk_test_..." \
-d '{"amount": 2500}'Same key returns the same response, preventing duplicate charges.
Every financial transaction creates balanced ledger entries:
Charge $100:
DR Funds Receivable $100.00
CR Merchant Payable $ 97.10
CR Revenue: Fees $ 2.90
Webhooks are signed for verification:
Stripe-Signature: t=1234567890,v1=abc123...
Merchants can verify using HMAC-SHA256 with their webhook secret.
# Terminal 1
PORT=3001 npm run dev
# Terminal 2
PORT=3002 npm run dev
# Terminal 3
PORT=3003 npm run dev| Variable | Default | Description |
|---|---|---|
| PORT | 3001 | Server port |
| POSTGRES_HOST | localhost | PostgreSQL host |
| POSTGRES_PORT | 5432 | PostgreSQL port |
| POSTGRES_USER | stripe | PostgreSQL user |
| POSTGRES_PASSWORD | stripe_dev_password | PostgreSQL password |
| POSTGRES_DB | stripe_db | PostgreSQL database |
| REDIS_URL | redis://localhost:6379 | Redis URL |
| PROCESSING_FEE_PERCENT | 2.9 | Fee percentage |
| PROCESSING_FEE_FIXED | 30 | Fixed fee in cents |
See architecture.md for detailed system design documentation.
See claude.md for development insights and design decisions.
- Stripe API Design - The gold standard for payment API design with consistent patterns and excellent documentation
- Designing Robust and Predictable APIs with Idempotency - Stripe's approach to building retry-safe APIs
- Implementing Stripe-like Idempotency Keys in Postgres - Deep dive into idempotency implementation with database transactions
- Accounting for Developers - Modern Treasury's guide to double-entry bookkeeping
- Life of a Payment - Airbnb's approach to avoiding double payments
- Distributed Transactions at Scale in Amazon DynamoDB - Patterns for distributed transaction consistency
- Designing Data-Intensive Applications - Martin Kleppmann's essential book on building reliable systems