Built by @jannisarndt
A modern e-commerce backend API built with Hono, Cloudflare Workers, and Stripe. This project started as a learning exercise to understand how platforms like Shopify structure their merchant infrastructure, and grew into a fully functional API that handles the complete e-commerce flow.
As a junior developer curious about how large-scale e-commerce platforms work under the hood, I decided to build my own merchant API from scratch. The goal was to understand the core concepts: product catalogs, inventory management, cart sessions, checkout flows, and payment processing.
This isn't meant to compete with Shopify or similar platforms. It's a learning project that implements real-world patterns and might be useful for small projects, prototypes, or as a reference for others exploring similar concepts.
- Product Management - Create, update, and organize products with variants and images
- Inventory Tracking - Stock management with reservation system to prevent overselling
- Cart System - Session-based shopping carts with expiration handling
- Stripe Checkout - Full integration with Stripe for secure payment processing
- Webhook Handling - Automated order fulfillment via Stripe webhooks
- GDPR Compliance - PII encryption at rest for customer data
- Admin Authentication - API key-based access control for sensitive operations
- OpenAPI Documentation - Auto-generated API docs with Scalar UI
- Runtime: Cloudflare Workers
- Framework: Hono with Zod OpenAPI
- Database: PostgreSQL with Drizzle ORM
- Payments: Stripe Checkout
- Language: TypeScript
- Node.js 18+
- A PostgreSQL database (Neon, Supabase, or any provider)
- Stripe account with API keys
- Cloudflare account (for deployment)
# Clone the repository
git clone https://github.com/bttrlabs/merchant.git
cd merchant
# Install dependencies
npm install
# Set up environment variables
cp .dev.vars.example .dev.varsCreate a .dev.vars file with the following:
DATABASE_URL=postgresql://user:password@host:5432/database
SERVICE_NAME=BTTR Merchant
SERVICE_VERSION=1.0.0
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
ADMIN_API_KEY=your-secure-api-key
ENCRYPTION_KEY=your-32-byte-encryption-key# Generate migrations
pnpm run db:generate
# Apply migrations
pnpm run db:migrate# Start local development server
pnpm run devThe API will be available at http://localhost:8787. OpenAPI documentation is served at /.
# Deploy to Cloudflare Workers
pnpm run deployAll endpoints are versioned under /v1/. Here's a quick overview:
| Resource | Description |
|---|---|
GET /v1/products |
List all products |
POST /v1/products |
Create a product (admin) |
GET /v1/products/{slug} |
Get product details |
POST /v1/cart |
Create a shopping cart |
POST /v1/cart/items |
Add item to cart |
POST /v1/cart/checkout |
Start Stripe checkout |
GET /v1/inventory |
List inventory levels |
GET /v1/orders |
List orders (admin) |
GET /v1/health |
Health check |
For complete API documentation, visit /docs when running the server.
- Customer creates a cart and adds items
- Cart items are validated against available inventory
- On checkout, stock is reserved for 30 minutes
- Customer is redirected to Stripe Checkout
- Stripe webhook confirms payment
- Reservations are converted to permanent stock deductions
- Order status is updated to "paid"
To prevent overselling during checkout, the API implements a reservation system:
- Stock is temporarily reserved when checkout begins
- Reservations expire after 30 minutes if payment isn't completed
- Expired reservations automatically restore inventory
- This ensures accurate stock counts even with concurrent checkouts
Customer PII (email, name, address) is encrypted using AES-256-GCM before storage. Data is decrypted only when accessed through authenticated admin endpoints.
src/
├── db/
│ ├── client.ts # Database connection
│ ├── schemas.ts # Zod schemas for validation
│ └── tables.ts # Drizzle table definitions
├── lib/
│ ├── create-app.ts # Hono app factory
│ ├── crypto.ts # PII encryption utilities
│ └── inventory.ts # Stock reservation logic
├── middleware/
│ ├── admin-auth.ts # API key authentication
│ └── logger.ts # Request logging
├── routes/
│ ├── products/ # Product CRUD
│ ├── variants/ # Variant management
│ ├── images/ # Product images
│ ├── cart/ # Cart operations
│ ├── inventory/ # Stock management
│ ├── reservations/ # Stock reservations
│ ├── orders/ # Order management
│ ├── webhooks/ # Stripe webhooks
│ └── health.ts # Health check
└── index.ts # App entry point
Contributions are welcome! This is a learning project, so I'm open to suggestions, improvements, and fixes.
- Fork the repository
- Clone your fork locally
- Create a feature branch (
git checkout -b feature/your-feature) - Make your changes
- Commit your changes (
git commit -m "Add your feature") - Push to your fork (
git push origin feature/your-feature) - Open a Pull Request
Whether it's fixing a typo, improving documentation, or adding new features, all contributions are appreciated.
Building this project taught me a lot about:
- Designing RESTful APIs with proper resource modeling
- Handling concurrent operations (inventory reservations)
- Payment integration patterns and webhook security
- Data encryption for compliance requirements
- Edge computing with Cloudflare Workers
- Database design with relations and constraints
MIT
If you found this helpful or have questions, feel free to open an issue. I'm always happy to discuss the implementation or help others learning similar concepts.