--- title: "Stop Wrestling with Puppeteer: Generate PDFs with One API Call" published: false description: "How to generate invoices, reports, and documents as PDFs from HTML, Markdown, or JSON data — without managing headless browsers." tags: webdev, api, node, tutorial cover_image: # (add a cover image URL) --- Every developer has the same PDF story. It starts innocently: > "Can we add a 'Download as PDF' button?" Three days later, you're debugging Chrome memory leaks in production, your Puppeteer instance is eating 2GB of RAM, and the PDFs look different on every server. I got tired of this cycle, so I built [DocFast](https://docfast.dev) — a PDF API that takes HTML, Markdown, or structured data and returns a PDF. No headless browser setup, no dependencies. Here's what I learned, and how you can generate PDFs in about 30 seconds. ## The Simple Version ```bash curl -X POST https://docfast.dev/v1/convert/html \ -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"html": "

Hello World

This is a PDF.

"}' \ -o hello.pdf ``` That's it. JSON in, PDF out. ## Three Ways to Generate PDFs DocFast has three conversion endpoints, each for a different use case: ### 1. HTML → PDF You have full control. Pass any HTML with optional CSS: ```javascript const response = await fetch('https://docfast.dev/v1/convert/html', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ html: `

Monthly Report

Revenue: $12,345

Users1,234
MRR$5,670
`, css: 'body { font-family: Georgia, serif; padding: 40px; }', format: 'A4' }) }); const pdf = await response.arrayBuffer(); fs.writeFileSync('report.pdf', Buffer.from(pdf)); ``` ### 2. Markdown → PDF This is my favorite endpoint. Write Markdown, get a styled PDF with syntax highlighting: ```javascript const markdown = ` # Project Proposal ## Overview We propose building a **real-time dashboard** for monitoring API usage. ## Timeline | Phase | Duration | Cost | |-------|----------|------| | Design | 2 weeks | $3,000 | | Build | 4 weeks | $8,000 | | Test | 1 week | $1,500 | ## Code Sample \`\`\`javascript const analytics = new Analytics({ key: 'abc123' }); analytics.track('pdf_generated', { format: 'A4' }); \`\`\` `; const response = await fetch('https://docfast.dev/v1/convert/markdown', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ markdown }) }); ``` Tables, code blocks, images — it all renders beautifully. ### 3. URL → PDF Need to snapshot a webpage? Just pass the URL: ```bash curl -X POST https://docfast.dev/v1/convert/url \ -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com", "waitUntil": "networkidle0"}' \ -o page.pdf ``` It handles JavaScript-rendered pages too (SPAs, dashboards, etc). ## The Killer Feature: Invoice Templates This is what I wish existed years ago. Instead of building invoice HTML from scratch, you pass JSON data and get a professional invoice: ```javascript const response = await fetch('https://docfast.dev/v1/templates/invoice/render', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ data: { invoiceNumber: 'INV-2026-042', date: '2026-02-14', dueDate: '2026-03-14', from: { name: 'Your Company', address: '123 Main St', email: 'billing@yourco.com' }, to: { name: 'Client Corp', address: '456 Oak Ave', email: 'ap@client.com' }, items: [ { description: 'Web Development', quantity: 40, unitPrice: 95, taxRate: 20 }, { description: 'Hosting', quantity: 1, unitPrice: 29 } ], currency: '€', notes: 'Payment due within 30 days.', paymentDetails: 'IBAN: AT12 3456 7890 1234 5678' } }) }); ``` No HTML. No CSS. Just data → PDF. ## Integrating Into Your App Here's a minimal Express.js endpoint that generates and returns an invoice: ```javascript app.get('/api/invoice/:id', async (req, res) => { const invoice = await db.getInvoice(req.params.id); const pdfResponse = await fetch('https://docfast.dev/v1/templates/invoice/render', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.DOCFAST_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ data: invoice }) }); res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', `attachment; filename=invoice-${invoice.invoiceNumber}.pdf`); pdfResponse.body.pipe(res); }); ``` 12 lines. Your users can download invoices. ## Why Not Just Use Puppeteer? You can! But here's what you're signing up for: - **Memory:** Each Chrome instance uses 200-500MB RAM - **Cold starts:** Launching a browser takes 1-3 seconds - **Stability:** Chrome crashes, zombie processes, OOM kills - **DevOps:** Managing Chrome versions, fonts, dependencies in Docker - **Concurrency:** Need multiple PDFs at once? Now you're managing a browser pool DocFast handles all of this. Persistent browser pool, sub-second generation, no infrastructure to manage. ## Pricing - **Free:** 100 PDFs/month, all endpoints, all templates - **Pro:** $9/month for 10,000 PDFs/month No per-page fees. No credit card for the free tier. [Get your API key here](https://docfast.dev). --- If you have questions about the API or want to see specific templates added, drop a comment. I'm actively building based on user feedback. Happy PDF-ing! 📄