// api reference

HTML to PDF API

One endpoint. Send raw HTML or a Nunjucks template plus JSON data and get back a pixel-perfect PDF. Full Chromium rendering. Modern CSS, web fonts, and even async JavaScript like charts and QR codes.

Quick Start

Base URL

https://e.customjs.io/html2pdf

Get your API key from app.customjs.space, 600 free conversions every month, no credit card.

Authentication

Pass your API key in the x-api-key header. The response is the raw PDF binary, so pipe it to a file.

curl -X POST https://e.customjs.io/html2pdf \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{ "input": { "html": "<h1>Hello World</h1>" } }' \
  > output.pdf

Rate Limiting

Every response includes your current usage in the rate-limit headers.

Response HeaderDescription
x-ratelimit-limitMaximum requests allowed in the current window
x-ratelimit-usedRequests used in the current window
x-ratelimit-remainingRequests remaining in the current window

POST /html2pdf

Send HTML, get a PDF. The whole document is rendered in a real Chromium instance, so your CSS, layout, and fonts come out exactly as in the browser.

Request body

FieldTypeDescription
input.htmlstringRequired. The HTML content to convert to PDF
input.dataobjectTemplate data. When provided, the HTML is rendered with the Nunjucks template engine before conversion
input.configobjectOptional page configuration
input.config.pdfWidthMmnumberPage width in millimeters. Defaults to A4 (210)
input.config.pdfHeightMmnumberPage height in millimeters. Defaults to A4 (297)

Example. Simple HTML

curl -X POST https://e.customjs.io/html2pdf \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "input": {
      "html": "<h1>Hello World</h1>"
    }
  }' \
  > output.pdf

Templating with Nunjucks

Store the design once and send only your data. Add a data object and reference it in the HTML with {{ variable }} placeholders. Perfect for invoices, reports, and certificates.

curl -X POST https://e.customjs.io/html2pdf \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "input": {
      "html": "<h1>Hello {{ name }}</h1><p>Total: {{ total }}</p>",
      "data": { "name": "John", "total": 100 },
      "config": { "pdfWidthMm": 150, "pdfHeightMm": 150 }
    }
  }' \
  > output.pdf

Advanced rendering

Because conversion runs in a real Chromium instance, your template can execute JavaScript. Load external libraries, draw charts, or generate QR codes at render time.

External JavaScript libraries (QR codes)

Import ES modules straight from a CDN inside a <script type="module"> tag.

<script type="module">
  import QRCode from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';

  // Generate a QR code at render time
  const qrDataUrl = await QRCode.toDataURL('https://example.com', {
    width: 150,
    margin: 1
  });
  document.getElementById('qr').src = qrDataUrl;
</script>

<img id="qr" alt="QR Code" />

Async rendering with window.__RENDER_DONE__

When your template does async work (QR codes, charts, API calls), set window.__RENDER_DONE__ = true when the content is ready. The generator waits for this flag before capturing the page.

<script type="module">
  import QRCode from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';

  // Tell the generator we're not ready yet
  window.__RENDER_DONE__ = false;

  async function generateQR() {
    const qrDataUrl = await QRCode.toDataURL('https://example.com');
    document.getElementById('qr').src = qrDataUrl;

    // Signal that rendering is complete
    window.__RENDER_DONE__ = true;
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', generateQR);
  } else {
    generateQR();
  }
</script>

โš ๏ธ Important: without setting window.__RENDER_DONE__ = true, the PDF may be blank or incomplete because the generator won't wait for async operations to finish.

โ†’ Read the complete QR Code guide

Response Format

On success the API responds with Content-Type: application/pdf and the raw PDF bytes in the body. Pipe it to a file or stream it to your storage.

HTTP/1.1 200 OK
Content-Type: application/pdf
x-ratelimit-limit: 500
x-ratelimit-used: 12
x-ratelimit-remaining: 488

%PDF-1.4 ...binary...

Response Headers

HeaderDescription
Content-Typeapplication/pdf on success
x-ratelimit-limitMaximum requests per window
x-ratelimit-usedRequests used in the current window
x-ratelimit-remainingRequests remaining in the current window

Error Codes

CodeMeaning
200Success. Body contains the PDF binary
400Bad request. Missing or invalid input.html
401Unauthorized. Missing or invalid API key
500Internal error. Rendering failed

// try it first

Prefer to play before you code?

Open the interactive playground on the product page. Paste your HTML, watch the PDF render live, tweak the page size, and copy the generated curl or SDK snippet straight into your stack.

playground.curl
curl -X POST https://e.customjs.io/html2pdf \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "input": {
      "html": "<h1>Invoice #{{ id }}</h1>",
      "data": { "id": "1042" }
    }
  }' > invoice.pdf

600 free conversions / month ยท no credit card

Frequently Asked Questions