5.8 KiB
| title | published | description | tags | cover_image |
|---|---|---|---|---|
| Stop Wrestling with Puppeteer: Generate PDFs with One API Call | false | How to generate invoices, reports, and documents as PDFs from HTML, Markdown, or JSON data — without managing headless browsers. | webdev, api, node, tutorial |
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 — 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
curl -X POST https://docfast.dev/v1/convert/html \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Hello World</h1><p>This is a PDF.</p>"}' \
-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:
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: `
<h1 style="color: navy;">Monthly Report</h1>
<p>Revenue: <strong>$12,345</strong></p>
<table>
<tr><td>Users</td><td>1,234</td></tr>
<tr><td>MRR</td><td>$5,670</td></tr>
</table>
`,
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:
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:
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:
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:
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.
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! 📄