Modern invoicing for freelancers and independent creators. Built on the Cloudflare developer platform.
- Authentication: Email magic link authentication (passwordless)
- Multi-tenant: Each user only sees their own data
- Clients: Create, edit, archive clients with full contact details
- Invoices: Full invoice lifecycle - draft, send, track, and get paid
- PDF Generation: Real PDF invoices via Cloudflare Browser Rendering API, stored in R2
- Email Notifications: Invoice delivery, reminders, payment receipts via Resend
- Payments: Stripe Checkout integration with webhook handling
- Reminders: Automatic payment reminders using Durable Objects
- Dashboard: KPIs and analytics at a glance
kivo/
├── apps/
│ ├── api/ # Cloudflare Workers backend (Hono) + static assets
│ └── web/ # React frontend (Vite + TanStack)
└── packages/
└── shared/ # Shared types and utilities
Kivo deploys as a single Cloudflare Worker that serves both the API and frontend:
/api/*→ Hono API routes/health→ Health check endpoint/*→ Static assets (React SPA)
This unified deployment provides:
- Single URL for the entire application
- No CORS configuration needed (same origin)
- Simplified deployment process
- Reduced infrastructure complexity
Backend
- Cloudflare Workers (TypeScript, ES Modules)
- Hono for routing
- D1 for relational data
- R2 for PDF/asset storage
- Browser Rendering API for PDF generation
- Durable Objects for reminder scheduling
- Cron Triggers for periodic reconciliation
- Static Assets for serving the frontend
Frontend
- React + Vite
- TanStack Router + Query
- Tailwind CSS + shadcn/ui
- Form validation with Zod
- react-hook-form
Email + Payments
- Resend for transactional email
- Stripe for payments
- Node.js 18+
- Wrangler CLI (
npm install -g wrangler) - Cloudflare account
- Stripe account
- Resend account
git clone <repository-url>
cd kivo
npm install# Login to Cloudflare
wrangler login
# Create D1 database
wrangler d1 create kivo-db
# Copy the database_id to wrangler.jsonc
# Create R2 bucket
wrangler r2 bucket create kivo-storageUpdate apps/api/wrangler.jsonc with your D1 database ID.
Set secrets using Wrangler:
cd apps/api
# JWT secret for auth tokens
wrangler secret put JWT_SECRET
# (Enter a secure random string)
# Resend API key for email
wrangler secret put RESEND_API_KEY
# (Get from https://resend.com/api-keys)
# Stripe secret key
wrangler secret put STRIPE_SECRET_KEY
# (Get from https://dashboard.stripe.com/apikeys)
# Stripe webhook secret
wrangler secret put STRIPE_WEBHOOK_SECRET
# (Get after creating webhook endpoint)
# Cloudflare Browser Rendering API token (for PDF generation)
wrangler secret put CF_API_TOKEN
# (Create at https://dash.cloudflare.com/profile/api-tokens with Browser Rendering permissions)# Local development
npm run db:migrate:local -w apps/api
# Production
npm run db:migrate -w apps/api
# Seed sample data (optional)
npm run db:seed:local -w apps/apiCreate a webhook endpoint in Stripe Dashboard:
- URL:
https://your-worker.your-subdomain.workers.dev/api/webhooks/stripe - Events to listen for:
checkout.session.completedcheckout.session.expiredpayment_intent.payment_failed
# Start both API and web dev servers
npm run dev- API: http://localhost:8787
- Web: http://localhost:5173
The project includes a GitHub Actions workflow that automatically deploys to Cloudflare when you push to main.
Setup GitHub Secrets:
- Go to your repository on GitHub → Settings → Secrets and variables → Actions
- Add these secrets:
CLOUDFLARE_API_TOKEN: Create at Cloudflare API Tokens with "Edit Cloudflare Workers" permissionsCLOUDFLARE_ACCOUNT_ID: Find in the Cloudflare dashboard URL or Workers overview page
Once configured, every push to main will automatically:
- Build the shared package
- Build the web frontend
- Deploy to Cloudflare Workers
Kivo deploys as a single Cloudflare Worker with static assets:
npm run deployThis command will:
- Build the shared package
- Build the web frontend to
apps/web/dist - Deploy the combined worker (API + static assets) to Cloudflare
Your app will be available at: https://kivo.<your-subdomain>.workers.dev
Update production environment variables in apps/api/wrangler.jsonc:
| Variable | Description |
|---|---|
JWT_SECRET |
Secret for signing JWT tokens |
RESEND_API_KEY |
Resend API key for sending emails |
STRIPE_SECRET_KEY |
Stripe secret key |
STRIPE_WEBHOOK_SECRET |
Stripe webhook signing secret |
CF_ACCOUNT_ID |
Cloudflare account ID (for Browser Rendering API) |
CF_API_TOKEN |
Cloudflare API token with Browser Rendering permissions |
FRONTEND_URL |
Frontend URL (for CORS and email links) |
API_URL |
API URL (for generating links) |
The frontend proxies API requests to /api in development. In production, both frontend and API are served from the same worker, so no additional configuration is needed.
- Sign Up: Enter your email to receive a magic link
- Verify: Click the link in your email to authenticate
- Settings: Configure your business profile and defaults
- Create Client: Add your first client with contact details
- Create Invoice: Generate an invoice with line items
- Send Invoice: Send via email to your client
- Client View: Client opens the public link, views invoice
- Payment: Client pays via Stripe Checkout
- Confirmation: Both parties receive email confirmations
# Run all tests
npm test
# Run shared package tests
npm test -w packages/sharedMIT
