Design invoices visually. Generate PDFs via API.
Stop wrestling with wkhtmltopdf configs and Puppeteer headaches.
make-billis an open-source, visual invoice builder with an API-first approach to PDF generation.
π― What is make-bill?
Have you ever spent hours trying to generate pixel-perfect invoices programmatically? Fought with HTML-to-PDF libraries that never quite render things correctly? make-bill was built to solve exactly that.
Itβs a modern web application that combines:
- A visual drag-and-drop editor for designing invoice templates
- Pixel-perfect PDF generation via a simple REST API
- Dynamic data binding so your templates come alive with real data
Think of it as Canva meets Stripe Invoicesβdesign once, generate forever.
β¨ Features at a Glance
| Feature | Description |
|---|---|
| π¨ Visual Editor | Drag-and-drop interface with absolute positioning on an A4 canvas |
| π Multiple Page Sizes | A4, A3, A5, Letter, Legalβwith portrait and landscape orientations |
| π Data Binding | Bind text fields to data paths like invoice.customer.name |
| π Tables | Dynamic tables that expand with your data arrays |
| πΌοΈ Images | Upload logos, signatures, or any image assets |
| π PDF Generation | Server-side rendering with Puppeteer for consistent output |
| πΎ Template Management | Save, load, and version your templates |
| π Authentication | Supabase-powered user authentication |
| β‘ REST API | Generate PDFs programmatically with a single POST request |
π Getting Started
Prerequisites
- Node.js v18 or higher
- Bun (recommended) or npm/yarn/pnpm
- A Supabase project (for authentication and template storage)
Installation
-
Clone the repository
git clone https://github.com/pratikstemkar/make-bill.git cd make-bill -
Install dependencies
bun install # or npm install -
Set up environment variables
Copy the example environment file and fill in your credentials:
cp .env.example .env.localYour
.env.localshould contain:NEXT_PUBLIC_SUPABASE_URL=your_supabase_url NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key -
Start the development server
bun dev # or npm run dev -
Open your browser
Navigate to http://localhost:3000 and start building!
π¨ Using the Visual Editor
The heart of make-bill is its visual editor. Hereβs how to create your first template:
1. Open the Editor
Click βOpen Editorβ from the landing page or navigate directly to /editor.
2. Add Elements
The left panel contains your toolbox. Drag elements onto the canvas:
- Text β Static text or dynamic data bindings
- Image β Upload logos, product images, or signatures
- Line β Horizontal separators for visual structure
- Table β Dynamic tables that expand with your data
3. Configure Page Settings
At the top of the left panel, configure your document:
- Page Size β A4, A3, A5, Letter, or Legal
- Orientation β Portrait or Landscape
- Margins β Control the printable area
4. Bind Data to Elements
Select a text element and use the Inspector panel (right side) to set a binding path:
invoice.customer.name
invoice.number
invoice.date
invoice.total
When you generate the PDF via API, these placeholders are replaced with actual data.
5. Preview Your Template
Click βPreviewβ to see how your invoice will look with sample data.
6. Save Your Template
Hit βSave Templateβ to persist your design. Templates are versioned, so you can iterate without breaking existing integrations.
π‘ API Usage
Once youβve designed and saved a template, generate PDFs with a simple HTTP request.
Generate a PDF
curl -X POST https://your-domain.com/api/generate-pdf \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "invoice_v1",
"data": {
"invoice": {
"number": "INV-2024-001",
"date": "2024-01-15",
"customer": {
"name": "Acme Corporation",
"address": "123 Business Street"
},
"items": [
{ "name": "Consulting Services", "qty": 10, "price": 150 },
{ "name": "Development Work", "qty": 20, "price": 100 }
],
"total": 3500
}
}
}'
Response
The API returns the PDF as a binary stream with Content-Type: application/pdf.
π Element Types
Text Element
Static or dynamic text content.
{
type: "text",
content: "Invoice", // Static content
binding: "invoice.number", // OR dynamic binding
fontSize: 16,
fontWeight: "bold" | "normal",
align: "left" | "center" | "right"
}
Image Element
Embed images with optional aspect ratio locking.
{
type: "image",
src: "https://...", // Image URL or base64
maintainAspectRatio: true
}
Line Element
Horizontal separator lines.
{
type: "line",
thickness: 2 // Line thickness in pixels
}
Table Element
Dynamic tables bound to an array in your data.
{
type: "table",
columns: ["Item", "Qty", "Price"],
binding: "invoice.items" // Path to array data
}
ποΈ Project Structure
make-bill/
βββ app/ # Next.js App Router pages
β βββ api/ # API routes (PDF generation, etc.)
β βββ editor/ # Visual template editor
β βββ login/ # Authentication pages
β βββ templates/ # Template management
β βββ page.tsx # Landing page
βββ components/
β βββ editor/ # Editor components (Canvas, Inspector, etc.)
β βββ preview/ # PDF preview components
β βββ ui/ # Reusable UI components (shadcn/ui)
βββ lib/
β βββ api/ # API client utilities
β βββ htmlGenerator.ts # Server-side HTML generation for PDFs
β βββ types.ts # TypeScript type definitions
β βββ supabase/ # Supabase client configuration
βββ hooks/ # Custom React hooks
βββ store/ # Zustand state management
π οΈ Tech Stack
| Category | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript |
| Styling | Tailwind CSS v4 |
| UI Components | shadcn/ui + Radix UI |
| State Management | Zustand |
| Authentication | Supabase Auth |
| Database | Supabase (PostgreSQL) |
| PDF Generation | Puppeteer Core + @sparticuz/chromium |
| Icons | Lucide React |
| Notifications | Sonner |
π Environment Variables
| Variable | Description |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | Your Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Your Supabase anonymous/public key |
π¦ Available Scripts
# Development server
bun dev
# Production build
bun run build
# Start production server
bun start
# Lint the codebase
bun run lint
π’ Deployment
Vercel (Recommended)
make-bill is optimized for Vercel deployment. Simply connect your GitHub repository and Vercel will handle the rest.
Note: PDF generation uses
@sparticuz/chromiumwhich is specifically optimized for serverless environments like Vercel Functions.
Other Platforms
For other platforms, ensure you have:
- Node.js 18+ runtime
- Sufficient memory for Puppeteer (512MB+ recommended)
- Proper environment variable configuration
π€ Contributing
Contributions are welcome! Whether itβs bug fixes, new features, or documentation improvementsβweβd love to have your help.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
π License
This project is open source. Feel free to use, modify, and distribute as needed.
π‘ Why make-bill?
Because generating invoices should be simple.
No more:
- β Wrestling with wkhtmltopdf configurations
- β Debugging CSS rendering differences in headless Chrome
- β Manually crafting HTML templates with complex positioning
- β Dealing with font embedding issues
Instead:
- β Design visually, see exactly what youβll get
- β One API call to generate a PDF
- β Consistent, pixel-perfect output every time
- β Templates that non-developers can update
Built with β€οΈ for developers who hate fighting with PDF libraries.