One API Call. PDF + Excel.
Stop juggling Puppeteer, PDFKit, and ExcelJS. Generate documents in minutes, not weeks.
Delete 90% of your document code
Compare real-world implementations. No hidden helper functions or abstractions.
// invoice-pdf-service.ts - Puppeteer + Handlebars
// Full implementation for generating PDF invoices
import puppeteer, { Browser } from 'puppeteer';
import Handlebars from 'handlebars';
import * as fs from 'fs';
import * as path from 'path';
// ============================================
// Type Definitions
// ============================================
interface InvoiceItem {
description: string;
quantity: number;
unitPrice: number;
total: number;
}
interface InvoiceData {
invoiceNumber: string;
customerName: string;
customerEmail: string;
companyName: string;
companyAddress: string;
items: InvoiceItem[];
subtotal: number;
tax: number;
total: number;
dueDate: string;
issueDate: string;
}
// ============================================
// Puppeteer Browser Management
// ============================================
let browser: Browser | null = null;
async function getBrowser(): Promise<Browser> {
if (!browser) {
browser = await puppeteer.launch({
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
],
});
}
return browser;
}
// ============================================
// Template Loading & Compilation
// ============================================
const pdfTemplatePath = path.join(__dirname, 'templates', 'invoice-pdf.hbs');
let pdfTemplate: Handlebars.TemplateDelegate;
function loadTemplates() {
pdfTemplate = Handlebars.compile(
fs.readFileSync(pdfTemplatePath, 'utf-8')
);
}
// Register Handlebars helpers for formatting
Handlebars.registerHelper('formatCurrency', (value: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(value);
});
Handlebars.registerHelper('formatDate', (date: string) => {
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
});
Handlebars.registerHelper('multiply', (a: number, b: number) => a * b);
// Load templates on module init
loadTemplates();
// ============================================
// PDF Generation with Puppeteer
// ============================================
export async function generateInvoicePDF(data: InvoiceData): Promise<Buffer> {
const browser = await getBrowser();
const page = await browser.newPage();
try {
// Render HTML from Handlebars template
const html = pdfTemplate(data);
// Set viewport for consistent rendering
await page.setViewport({ width: 794, height: 1123 }); // A4 size
// Set content and wait for resources
await page.setContent(html, {
waitUntil: 'networkidle0',
timeout: 30000,
});
// Add custom styles for print
await page.addStyleTag({
content: `
@page { margin: 0; }
body { margin: 20mm; }
`,
});
// Generate PDF buffer
const pdfBuffer = await page.pdf({
format: 'A4',
printBackground: true,
preferCSSPageSize: true,
margin: {
top: '20mm',
right: '20mm',
bottom: '20mm',
left: '20mm',
},
});
return Buffer.from(pdfBuffer);
} catch (error) {
throw new Error(`PDF generation failed: ${(error as Error).message}`);
} finally {
await page.close();
}
}
// ============================================
// Save PDF to file or upload to S3
// ============================================
export async function saveInvoicePDF(data: InvoiceData): Promise<string> {
try {
if (!data.invoiceNumber) {
throw new Error('Missing required invoice data');
}
console.log(`Generating PDF for invoice ${data.invoiceNumber}...`);
const pdfBuffer = await generateInvoicePDF(data);
// Save to file or upload to S3
const filename = `invoice-${data.invoiceNumber}.pdf`;
fs.writeFileSync(path.join(__dirname, 'output', filename), pdfBuffer);
console.log(`Invoice PDF saved: ${filename}`);
return filename;
} catch (error) {
console.error('Failed to generate invoice:', error);
throw new Error(`PDF generation failed: ${(error as Error).message}`);
}
}
// Cleanup on process exit
process.on('exit', async () => {
if (browser) await browser.close();
});+ Not shown: Handlebars template file (~100 lines), environment setup, dependency management, browser/service initialization, and production deployment configuration.
// invoice-pdf-service.ts - RenderDoc
// Generate invoice PDF with one API call
// Types
interface InvoiceData {
invoiceNumber: string;
customerName: string;
items: Array<{
description: string;
quantity: number;
unitPrice: number;
}>;
subtotal: number;
tax: number;
total: number;
dueDate: string;
}
// Generate PDF - that's it!
export async function generateInvoicePDF(data: InvoiceData) {
const response = await fetch('https://api.renderdoc.dev/api/v1/documents/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.RENDERDOC_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 'invoice-template',
format: 'pdf',
variables: data,
}),
});
if (!response.ok) {
throw new Error(`Failed to generate PDF: ${response.statusText}`);
}
const { jobId, downloadUrl } = await response.json();
return { jobId, downloadUrl };
}
// Variables like formatting, calculations, and
// conditional logic are handled in the template designer.
// No Handlebars helpers. No Puppeteer. No DocRaptor.
// Just your data and one API call.Get Started in 5 Minutes
Three steps to generating your first document.
curl -X POST https://api.renderdoc.dev/api/v1/documents/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "invoice-template",
"format": "pdf",
"variables": {
"invoiceNumber": "INV-001",
"items": [{ "name": "Product", "quantity": 2, "price": 49.99 }],
"total": 99.98
}
}'
# Response:
# {
# "jobId": "doc_abc123",
# "status": "completed",
# "downloadUrl": "https://..."
# }Built for Developers
Everything you need for a smooth integration.
Multiple Output Formats
Same template, different formats. Choose what works for your use case.
Generate Templates with AI
Feed our JSON schema to ChatGPT, Claude, or Gemini. Generate complex templates with calculated fields, conditionals, and loops in seconds.
Describe Your Template
"Create an invoice PDF with line items, tax calculation, and company logo"
AI Generates JSON
LLM outputs valid RenderDoc template schema with all components
Import & Refine
Paste JSON into the designer. Tweak visually. Done.
Ready to ship?
20 free documents per month. Full API access. No credit card required.