Generate

HTML to PDF

POST /v1/generate/html — turn your HTML into a vector PDF.

POST /v1/generate/html renders your HTML in managed headless Chrome and returns a 100% vector PDF: selectable text, embedded fonts, print-ready.

Basic request

curl -X POST https://api.pdf-forge.dev/v1/generate/html \
  -H "Authorization: Bearer $PDFFORGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1 class=\"text-2xl font-bold\">Report</h1><p>Q2 2026</p>",
    "options": { "format": "A4", "marginTop": "2cm", "marginBottom": "2cm" }
  }' \
  --output report.pdf
import { PDFForge } from "@pdfforge/core";

const client = new PDFForge(process.env.PDFFORGE_API_KEY!);

const pdf = await client.html(
  '<h1 class="text-2xl font-bold">Report</h1><p>Q2 2026</p>',
  { format: "A4", marginTop: "2cm", marginBottom: "2cm" },
);

// pdf.buffer (Uint8Array), pdf.pages, pdf.size, pdf.duration
await import("node:fs/promises").then((fs) =>
  fs.writeFile("report.pdf", pdf.buffer),
);

The response is the PDF itself

The API answers with the binary (application/pdf), not JSON. Metadata travels in headers: X-PDF-Pages, X-PDF-Size, X-Generation-Time-Ms and, when the pagination inspector runs, X-Pagination-Score / X-Pagination-Defects.

Request body

FieldTypeDescription
htmlstringRequired. Full document or fragment.
optionsobjectPage options — see below.
tailwindbooleanInject the Tailwind base so utility classes work.
tailwindModestring"jit" compiles the exact CSS for arbitrary/custom classes.
pageBreaksstring"smart" (default), "native" or "none" — see Pagination & fit.
cssstringExtra CSS injected into the document.
cssUrlstringURL of a stylesheet to load.
fontsstring[]Font names to load.
header / footerstringRunning header/footer HTML repeated on every page.
watermarkstringText stamped across pages.
passwordstringEncrypt the output PDF.
asyncbooleanQueue the generation as a job (see below).
webhookstringURL notified when an async job finishes.

options (page setup)

FieldTypeExample
formatstring"A4", "A5", "A3", "Letter", "Legal", "Tabloid"
width / heightstring"8cm" / "3cm" — overrides format
landscapebooleantrue
marginTop / marginBottom / marginLeft / marginRightstring"2cm", "1in"
printBackgroundbooleanPrint CSS backgrounds
scalenumber0.8
preferCssPageSizebooleanLet @page CSS win
fitstring"auto" (default) / "off" — shrink-to-fit, see Pagination & fit

Async mode

With "async": true the API responds 202 immediately:

{
  "job_id": "018f...",
  "status": "processing",
  "message": "PDF generation started. Poll GET /v1/jobs/018f... for status."
}

Poll GET /v1/jobs/:id (status: pendingprocessingcompleted / failed), or pass a webhook URL to receive { "job_id", "status", "completed_at" } when it finishes.

Async jobs report status only

The finished PDF is not stored for later download yet — async mode is for fire-and-forget flows where the webhook triggers a re-generation or a notification. To get the bytes, generate synchronously.

Next steps

On this page