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 };
}