Two weeks ago I was a developer who could build almost anything — but had never shipped my own product. So I stopped making excuses and built one, start to finish, in public.
It's called Billmint — a free invoice generator. No signup, works in any country with the right tax, and downloads a clean PDF. Here's how I built it, the technical decisions, and what I learned.
The problem
Every invoice tool I tried wanted me to sign up, add a card, or sit through ads — just to send one invoice. And most of them handled taxes like GST and VAT badly. I wanted something instant and free.
The stack (deliberately boring)
- TypeScript + Vite for the front end — no framework needed for a form-to-PDF tool
- jsPDF + jspdf-autotable for PDF generation, entirely in the browser
-
Netlify to deploy (drag-and-drop the
dist/folder — live in seconds) - Netlify Forms for an email waitlist with zero backend
No React, no server, no database. A single-page tool that does one thing well.
The interesting part: getting tax right
Most generic tools get Indian GST wrong. It needs to split into CGST + SGST for intra-state sales, or a single IGST line for inter-state — while other countries use a single VAT or Sales Tax line. I put all of that behind one pure function so the on-screen preview and the PDF can never disagree:
export function taxBreakdown(inv: Invoice): TaxLine[] {
const cfg = COUNTRIES[inv.country];
const { taxTotal } = computeTotals(inv);
// India, intra-state: split into equal CGST + SGST
if (cfg.splitTax && !inv.interState) {
const half = taxTotal / 2;
return [
{ label: `CGST (${inv.taxRate / 2}%)`, amount: half },
{ label: `SGST (${inv.taxRate / 2}%)`, amount: half },
];
}
// India inter-state → IGST; everywhere else → one line (VAT / Sales Tax)
const label = cfg.splitTax ? 'IGST' : cfg.taxLabel;
return [{ label: `${label} (${inv.taxRate}%)`, amount: taxTotal }];
}
Adding a new country is just one entry in a COUNTRIES config (label, rate, currency, locale). That's what makes it "work anywhere."
A gotcha: the ₹ symbol in PDFs
jsPDF's default font is ASCII-only, so the rupee symbol ₹ renders as garbage. Rather than embed a whole Unicode font on day one, I render amounts using the currency code via Intl.NumberFormat with currencyDisplay: 'code' — so the PDF shows INR 1,234.00 cleanly. On-screen (real fonts) it still shows ₹. A small trade-off that shipped faster.
Little touches that mattered
-
localStorageprofile — remembers the sender's details, logo, and accent colour so returning users don't re-type anything -
Logo upload + accent colours — read the file as a data URL, show it in the preview and drop it into the PDF with
doc.addImage - A "Made with Billmint" footer on every PDF — a tiny growth loop: every invoice a user sends quietly markets the tool
SEO from day one
I added keyword-targeted static landing pages (/freelancers/, /vat/, /gst/), a sitemap, structured data (JSON-LD), and Open Graph tags — then verified the property in Google Search Console. Won't rank overnight, but the foundation compounds.
The launch
I launched on Product Hunt, and submitted to a few directories for backlinks. In the first week, traffic went up ~5x — real users from India, the US, Nigeria, Pakistan, and more. Modest absolute numbers, but genuine global validation that people will use it.
Lessons
- "It already exists" isn't a reason to quit — it's proof people want it. You win by being simpler and actually shipping.
- Ship boring, ship fast. No framework, no backend, live in days.
- The product isn't the hard part — distribution is. Building took a few days; getting people to find it is the ongoing work.
Try it
getbillmint.netlify.app — free, no signup. I'd genuinely love feedback: what's missing, and would you use it over your current tool? 🙏
Top comments (0)