JavaScript Examples
Example code for using PDF API with JavaScript and Node.js.
JavaScript Examples
Use PDF API with Node.js, browsers, and popular frameworks.
Node.js with fetch
import { writeFile } from 'fs/promises';
async function generatePDF() {
const response = await fetch('https://api.pdfapi.dev/v1/pdf/markdown', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PDFAPI_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
markdown: `# Monthly Report
## Summary
- Total users: 1,234
- Revenue: $45,678
## Details
| Metric | Value |
|--------|-------|
| New signups | 156 |
| Churn rate | 2.3% |`,
theme: 'corporate',
options: {
format: 'A4',
margin: { top: '25mm', bottom: '25mm' }
}
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
const buffer = await response.arrayBuffer();
await writeFile('report.pdf', Buffer.from(buffer));
console.log('PDF saved to report.pdf');
}
generatePDF();
Browser Download
async function downloadPDF() {
const response = await fetch('https://api.pdfapi.dev/v1/pdf/markdown', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_xxx', // Use backend proxy in production!
'Content-Type': 'application/json',
},
body: JSON.stringify({
markdown: '# Hello World\n\nThis is my PDF!',
theme: 'default',
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.pdf';
a.click();
URL.revokeObjectURL(url);
}
Never expose API keys in client-side code. Use a backend proxy to make API calls.
Express.js Server
import express from 'express';
const app = express();
app.use(express.json());
app.post('/api/generate-pdf', async (req, res) => {
const { markdown, theme = 'default' } = req.body;
try {
const response = await fetch('https://api.pdfapi.dev/v1/pdf/markdown', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PDFAPI_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ markdown, theme }),
});
if (!response.ok) {
const error = await response.json();
return res.status(response.status).json(error);
}
const buffer = await response.arrayBuffer();
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename=document.pdf');
res.send(Buffer.from(buffer));
} catch (error) {
res.status(500).json({ error: { message: 'PDF generation failed' } });
}
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
Next.js API Route
// app/api/pdf/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const { markdown, theme } = await request.json();
const response = await fetch('https://api.pdfapi.dev/v1/pdf/markdown', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PDFAPI_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ markdown, theme }),
});
if (!response.ok) {
const error = await response.json();
return NextResponse.json(error, { status: response.status });
}
const buffer = await response.arrayBuffer();
return new NextResponse(buffer, {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename=document.pdf',
},
});
}
TypeScript Types
interface PDFOptions {
format?: 'A4' | 'A3' | 'A5' | 'Letter' | 'Legal' | 'Tabloid';
landscape?: boolean;
margin?: {
top?: string;
bottom?: string;
left?: string;
right?: string;
};
print_background?: boolean;
scale?: number;
header?: string;
footer?: string;
}
interface MarkdownToPDFRequest {
markdown: string;
theme?: string;
options?: PDFOptions;
}
interface APIError {
error: {
code: string;
message: string;
details?: Record<string, unknown>;
};
}
async function generatePDF(request: MarkdownToPDFRequest): Promise<ArrayBuffer> {
const response = await fetch('https://api.pdfapi.dev/v1/pdf/markdown', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PDFAPI_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(request),
});
if (!response.ok) {
const error: APIError = await response.json();
throw new Error(error.error.message);
}
return response.arrayBuffer();
}
Error Handling with Retry
async function generatePDFWithRetry(markdown, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('https://api.pdfapi.dev/v1/pdf/markdown', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PDFAPI_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ markdown }),
});
// Handle rate limiting
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
console.log(`Rate limited. Waiting ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
return await response.arrayBuffer();
} catch (error) {
if (attempt === maxRetries) throw error;
// Exponential backoff
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
}
}
}
Batch Processing
async function batchGeneratePDFs(documents) {
const results = [];
for (const doc of documents) {
try {
// Check rate limit before each request
const usage = await fetch('https://api.pdfapi.dev/v1/usage', {
headers: { 'Authorization': `Bearer ${process.env.PDFAPI_KEY}` },
}).then(r => r.json());
if (usage.data.rate_limit.current_usage >= usage.data.rate_limit.requests_per_minute - 1) {
console.log('Approaching rate limit, waiting...');
await new Promise(r => setTimeout(r, 60000));
}
const buffer = await generatePDF(doc);
results.push({ success: true, buffer });
} catch (error) {
results.push({ success: false, error: error.message });
}
// Small delay between requests
await new Promise(r => setTimeout(r, 100));
}
return results;
}
React Hook
import { useState, useCallback } from 'react';
interface UsePDFResult {
generatePDF: (markdown: string, theme?: string) => Promise<void>;
loading: boolean;
error: string | null;
}
export function usePDF(): UsePDFResult {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const generatePDF = useCallback(async (markdown: string, theme = 'default') => {
setLoading(true);
setError(null);
try {
const response = await fetch('/api/pdf', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ markdown, theme }),
});
if (!response.ok) {
const data = await response.json();
throw new Error(data.error.message);
}
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.pdf';
a.click();
URL.revokeObjectURL(url);
} catch (err) {
setError(err instanceof Error ? err.message : 'Generation failed');
} finally {
setLoading(false);
}
}, []);
return { generatePDF, loading, error };
}