Generate PDF Documents
Create professional PDF documents from templates using the RenderDoc API.
Overview
RenderDoc allows you to generate PDF documents dynamically from templates. This tutorial covers:
- Creating a PDF template (via AI, gallery, or manually)
- Generating PDFs via the API
- Batch document generation
- Webhook notifications for async processing
This is perfect for invoices, receipts, reports, contracts, certificates, and any document you need to generate programmatically.
Prerequisites
Before starting, make sure you have:
- An active RenderDoc account
- An API key with document generation permissions
- A published PDF template (see Create a Template)
How PDF Generation Works
RenderDoc uses templates to generate PDFs:
- Create a Template - Design your PDF layout in the visual editor
- Call the API - Send a request with your template ID and variables
- Receive the PDF - Get a download URL for the generated document
Template + Variables → API Call → PDF Document
Quick Start
Generate your first PDF in under a minute:
Step 1: Get Your Template ID
- Log in to your RenderDoc Dashboard
- Go to Templates
- Find your template and copy the Template ID (UUID or slug)
Step 2: Make an API Call
curl -X POST https://api.renderdoc.dev/api/v1/documents/generate \
-H "Authorization: Bearer rd_sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"templateId": "invoice-template",
"format": "pdf",
"variables": {
"invoiceNumber": "INV-2025-001",
"customerName": "Acme Corp",
"total": "$1,250.00"
}
}'
Step 3: Download Your PDF
The API returns a download URL:
{
"id": "doc_abc123xyz",
"status": "completed",
"format": "pdf",
"downloadUrl": "https://cdn.renderdoc.dev/documents/doc_abc123xyz.pdf",
"expiresAt": "2025-12-30T12:00:00.000Z"
}
Download your PDF from the downloadUrl before it expires.
Code Examples
JavaScript / Node.js
const API_KEY = process.env.RENDERDOC_API_KEY;
async function generateInvoice(invoiceData) {
const response = await fetch('https://api.renderdoc.dev/api/v1/documents/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 'invoice-template',
format: 'pdf',
variables: {
invoiceNumber: invoiceData.number,
invoiceDate: invoiceData.date,
customerName: invoiceData.customer.name,
customerAddress: invoiceData.customer.address,
items: invoiceData.items,
subtotal: invoiceData.subtotal,
tax: invoiceData.tax,
total: invoiceData.total,
},
}),
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.message);
}
console.log('PDF generated:', result.downloadUrl);
return result;
}
// Usage
generateInvoice({
number: 'INV-2025-001',
date: 'December 29, 2025',
customer: {
name: 'Acme Corp',
address: '123 Business St, New York, NY 10001',
},
items: [
{ description: 'Consulting', quantity: 10, price: '$1,500.00' },
{ description: 'Software License', quantity: 1, price: '$500.00' },
],
subtotal: '$2,000.00',
tax: '$170.00',
total: '$2,170.00',
});
Python
import requests
import os
API_KEY = os.environ.get('RENDERDOC_API_KEY')
API_URL = 'https://api.renderdoc.dev/api/v1/documents/generate'
def generate_invoice(invoice_data):
response = requests.post(
API_URL,
headers={
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json',
},
json={
'templateId': 'invoice-template',
'format': 'pdf',
'variables': {
'invoiceNumber': invoice_data['number'],
'invoiceDate': invoice_data['date'],
'customerName': invoice_data['customer']['name'],
'customerAddress': invoice_data['customer']['address'],
'items': invoice_data['items'],
'subtotal': invoice_data['subtotal'],
'tax': invoice_data['tax'],
'total': invoice_data['total'],
},
},
)
result = response.json()
if not response.ok:
raise Exception(result.get('message', 'Unknown error'))
print(f"PDF generated: {result['downloadUrl']}")
return result
# Usage
generate_invoice({
'number': 'INV-2025-001',
'date': 'December 29, 2025',
'customer': {
'name': 'Acme Corp',
'address': '123 Business St, New York, NY 10001',
},
'items': [
{'description': 'Consulting', 'quantity': 10, 'price': '$1,500.00'},
{'description': 'Software License', 'quantity': 1, 'price': '$500.00'},
],
'subtotal': '$2,000.00',
'tax': '$170.00',
'total': '$2,170.00',
})
Using the RenderDoc SDK
import RenderDoc from '@renderdoc/sdk';
const client = new RenderDoc(process.env.RENDERDOC_API_KEY);
const result = await client.documents.generate({
templateId: 'invoice-template',
format: 'pdf',
variables: {
invoiceNumber: 'INV-2025-001',
customerName: 'Acme Corp',
total: '$2,170.00',
},
});
console.log('Download URL:', result.downloadUrl);
Batch Generation
Generate multiple documents in a single API call:
const response = await fetch('https://api.renderdoc.dev/api/v1/documents/generate/batch', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 'invoice-template',
format: 'pdf',
documents: [
{
variables: {
invoiceNumber: 'INV-001',
customerName: 'Customer A',
total: '$500.00',
},
},
{
variables: {
invoiceNumber: 'INV-002',
customerName: 'Customer B',
total: '$750.00',
},
},
{
variables: {
invoiceNumber: 'INV-003',
customerName: 'Customer C',
total: '$1,200.00',
},
},
],
}),
});
const batch = await response.json();
console.log('Batch ID:', batch.batchId);
console.log('Documents:', batch.documents);
Batch Response
{
"batchId": "batch_xyz789",
"status": "processing",
"total": 3,
"completed": 0,
"failed": 0,
"documents": [
{ "id": "doc_001", "status": "pending" },
{ "id": "doc_002", "status": "pending" },
{ "id": "doc_003", "status": "pending" }
]
}
Check Batch Status
const status = await fetch(
`https://api.renderdoc.dev/api/v1/documents/batches/${batchId}`,
{
headers: { 'Authorization': `Bearer ${API_KEY}` },
}
).then(r => r.json());
console.log('Batch status:', status);
Webhook Notifications
Get notified when documents are generated:
Configure Webhook
- Go to Settings → Webhooks in your dashboard
- Add a webhook endpoint URL
- Select events:
document.generated,document.failed,batch.completed
Webhook Payload
{
"event": "document.generated",
"timestamp": "2025-12-29T10:30:00.000Z",
"data": {
"id": "doc_abc123",
"templateId": "invoice-template",
"format": "pdf",
"downloadUrl": "https://cdn.renderdoc.dev/documents/doc_abc123.pdf",
"expiresAt": "2025-12-30T10:30:00.000Z",
"metadata": {
"invoiceNumber": "INV-2025-001"
}
}
}
Webhook Handler Example
// Express.js webhook handler
app.post('/webhooks/renderdoc', (req, res) => {
const { event, data } = req.body;
switch (event) {
case 'document.generated':
console.log(`Document ready: ${data.downloadUrl}`);
// Download and store the PDF
// Notify the user
break;
case 'document.failed':
console.error(`Document failed: ${data.error}`);
// Handle the error
// Retry if appropriate
break;
case 'batch.completed':
console.log(`Batch complete: ${data.total} documents`);
// Process all documents
break;
}
res.status(200).send('OK');
});
Output Formats
RenderDoc supports multiple output formats:
| Format | Extension | Use Case |
|---|---|---|
pdf | Documents, invoices, reports | |
xlsx | .xlsx | Spreadsheets, data exports |
Generate Excel
const result = await fetch('https://api.renderdoc.dev/api/v1/documents/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 'report-template',
format: 'xlsx', // Excel format
variables: {
reportTitle: 'Monthly Sales Report',
month: 'December 2025',
data: salesData,
},
}),
}).then(r => r.json());
Custom Filenames
Specify a custom filename for the generated document:
const result = await fetch('https://api.renderdoc.dev/api/v1/documents/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 'invoice-template',
format: 'pdf',
filename: 'Invoice-{{invoiceNumber}}-{{customerName}}', // Dynamic filename
variables: {
invoiceNumber: 'INV-2025-001',
customerName: 'AcmeCorp',
},
}),
}).then(r => r.json());
// Result: Invoice-INV-2025-001-AcmeCorp.pdf
Metadata
Add metadata to track documents:
const result = await fetch('https://api.renderdoc.dev/api/v1/documents/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 'invoice-template',
format: 'pdf',
variables: { /* ... */ },
metadata: {
orderId: 'order-123',
customerId: 'cust-456',
source: 'api',
},
}),
}).then(r => r.json());
Metadata is returned in webhooks and can be used to correlate documents with your systems.
Real-World Example: Invoice System
Complete example integrating with an order system:
class InvoiceService {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.renderdoc.dev/api/v1';
}
async generateInvoice(order) {
// Calculate totals
const subtotal = order.items.reduce(
(sum, item) => sum + item.quantity * item.price,
0
);
const tax = subtotal * (order.taxRate / 100);
const total = subtotal + tax;
// Format items for template
const formattedItems = order.items.map(item => ({
description: item.name,
quantity: item.quantity,
unitPrice: this.formatCurrency(item.price),
amount: this.formatCurrency(item.quantity * item.price),
}));
// Generate PDF
const response = await fetch(`${this.baseUrl}/documents/generate`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId: 'invoice-template',
format: 'pdf',
filename: `Invoice-${order.invoiceNumber}`,
variables: {
invoiceNumber: order.invoiceNumber,
invoiceDate: this.formatDate(order.createdAt),
dueDate: this.formatDate(order.dueDate),
companyName: 'Your Company',
companyAddress: '123 Business St, City, ST 12345',
customerName: order.customer.name,
customerAddress: order.customer.address,
customerEmail: order.customer.email,
items: formattedItems,
subtotal: this.formatCurrency(subtotal),
taxRate: order.taxRate,
taxAmount: this.formatCurrency(tax),
total: this.formatCurrency(total),
paymentTerms: 'Payment due within 30 days.',
},
metadata: {
orderId: order.id,
customerId: order.customer.id,
},
}),
});
return response.json();
}
formatCurrency(amount) {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(amount);
}
formatDate(date) {
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
}
// Usage
const invoiceService = new InvoiceService(process.env.RENDERDOC_API_KEY);
const order = {
id: 'order-123',
invoiceNumber: 'INV-2025-001',
createdAt: new Date(),
dueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
taxRate: 8.5,
customer: {
id: 'cust-456',
name: 'John Doe',
email: '[email protected]',
address: '456 Customer Lane, New York, NY 10001',
},
items: [
{ name: 'Product A', quantity: 2, price: 99.99 },
{ name: 'Product B', quantity: 1, price: 149.99 },
],
};
invoiceService.generateInvoice(order)
.then(result => console.log('Invoice generated:', result.downloadUrl))
.catch(err => console.error('Error:', err));
PDF Design Best Practices
Layout
- Use standard page sizes - A4 for international, Letter for US
- Set appropriate margins - 40-60px for printing
- Keep it single page - When possible, fit content on one page
- Use visual hierarchy - Clear headings, grouped sections
Typography
- Professional fonts - Arial, Helvetica, Georgia work best
- Readable sizes - 10-12pt for body, 14-18pt for headings
- Consistent alignment - Right-align numbers for easy scanning
- Adequate spacing - White space improves readability
Branding
- Include your logo - Top-left is traditional for invoices
- Use brand colors - Sparingly for headers and accents
- Professional footer - Contact info and company details
Troubleshooting
PDF Not Generating
Solutions:
- ✅ Verify template exists and is published
- ✅ Check all required variables are provided
- ✅ Ensure API key has document generation permissions
- ✅ Check for validation errors in the response
Layout Issues in PDF
Solutions:
- ✅ Preview the template before generating
- ✅ Use fixed widths for columns in tables
- ✅ Avoid very long unbroken text
- ✅ Test with maximum expected data length
Missing Data in PDF
Solutions:
- ✅ Check variable names match exactly (case-sensitive)
- ✅ Verify nested object structure matches template
- ✅ Ensure array data is properly formatted
- ✅ Check the Variables tab in template editor
Download URL Expired
Solutions:
- ✅ Download immediately after generation
- ✅ Use webhooks for async processing
- ✅ Re-generate the document if needed
- ✅ Consider storing documents in your own storage
Next Steps
Now that you can generate PDF documents:
- Batch Generation - Generate multiple documents at once
- Excel Reports - Generate Excel spreadsheets
- Webhooks - Get notified when documents are ready
- API Reference - Full API documentation