Skip to content

An HTML to PDF API that is one POST request

CurlShot is an HTML to PDF API. Send your HTML in a POST request with format=pdf and the answer is the PDF file. A real browser lays the page out and prints it, so your CSS, web fonts, tables and images come out as they look on screen, with text you can select and search. Paper size, margins, orientation and background printing are options, and page breaks follow your CSS. It works from any language that can send an HTTP request.

Request
curl -X POST "https://curlshot.com/api/v1/screenshot" \
  -H "X-Access-Key: YOUR_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1>Invoice 1042</h1><p>Total: 120.00</p>","format":"pdf","pdf_paper_format":"a4","pdf_margin":"20mm"}' \
  --output invoice.pdf

How to convert HTML to PDF with the API in three steps

  1. 1

    Write the document as HTML and CSS, as you would a web page.

  2. 2

    Send it in a POST request with format set to pdf and the paper size you want.

  3. 3

    Save the PDF that comes back, or make one for every order, user or report.

One POST request, in your language

Send the HTML in the html field of a JSON body, with format set to pdf. The answer is the PDF file itself. Your access key goes in the X-Access-Key header, so it stays out of logs.

Node.js
const response = await fetch('https://curlshot.com/api/v1/screenshot', {
  method: 'POST',
  headers: { 'X-Access-Key': process.env.SCREENSHOT_ACCESS_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({ html: invoiceHtml, format: 'pdf', pdf_paper_format: 'a4', pdf_margin: '20mm' }),
})
if (!response.ok) throw new Error((await response.json()).error_message)
await writeFile('invoice.pdf', Buffer.from(await response.arrayBuffer()))
Python
response = requests.post(
    "https://curlshot.com/api/v1/screenshot",
    headers={"X-Access-Key": os.environ["SCREENSHOT_ACCESS_KEY"]},
    json={"html": invoice_html, "format": "pdf", "pdf_paper_format": "a4", "pdf_margin": "20mm"},
)
response.raise_for_status()
open("invoice.pdf", "wb").write(response.content)
PHP
$context = stream_context_create(['http' => [
    'method' => 'POST',
    'header' => "X-Access-Key: " . getenv('SCREENSHOT_ACCESS_KEY') . "\r\nContent-Type: application/json",
    'content' => json_encode(['html' => $invoiceHtml, 'format' => 'pdf', 'pdf_paper_format' => 'a4', 'pdf_margin' => '20mm']),
]]);
$pdf = file_get_contents('https://curlshot.com/api/v1/screenshot', false, $context);
if ($pdf === false) {
    throw new RuntimeException('Render failed: ' . ($http_response_header[0] ?? 'no response'));
}
file_put_contents('invoice.pdf', $pdf);

Paper sizes

pdf_paper_format takes any of these values. The default is a4; use letter for readers in the United States and Canada. pdf_landscape=true turns the paper on its side, and pdf_fit_one_page=true skips paper sizes and puts the whole document on one tall page.

Show the table (11 rows)
Paperpdf_paper_formatMillimetresInchesCSS pixels
A0a0841 × 118933.1 × 46.83178 × 4493
A1a1594 × 84123.4 × 33.12246 × 3178
A2a2420 × 59416.54 × 23.41588 × 2246
A3a3297 × 42011.7 × 16.541123 × 1588
A4a4210 × 2978.27 × 11.7794 × 1123
A5a5148 × 2105.83 × 8.27560 × 794
A6a6105 × 1484.13 × 5.83396 × 560
US Letterletter216 × 2798.5 × 11816 × 1056
US Legallegal216 × 3568.5 × 14816 × 1344
Tabloidtabloid279 × 43211 × 171056 × 1632
Ledgerledger432 × 27917 × 111632 × 1056

Margins, page breaks and print styles

The PDF is printed by a real browser, so the CSS you already know for printing works.

Show the table (6 rows)
You wantHow
A margin on every pagepdf_margin=20mm, or pdf_margin_top, _right, _bottom and _left for one side. Units: mm, cm, in or px.
A new page before each sectionCSS: section { break-before: page; }
A table row or a card never split in twoCSS: tr, .card { break-inside: avoid; }
Your @media print rules to applymedia_type=print. The default draws the screen styles.
No background colours, to save inkpdf_print_background=false. Backgrounds print by default.
Fonts and logosLink them with full https:// addresses; relative paths have nothing to resolve against.
  • Without a margin option the content runs to the edge of the paper.
  • HTML can be up to 2 MB. For many documents at once, use async=true with a webhook, or the bulk endpoint.
The first page of an A4 PDF rendered by the API
Page one of an A4 PDF made by the same browser engine. The text stays selectable and searchable.

What people use it for

  • Invoices and receipts from an HTML template
  • Reports and statements with tables and charts
  • Tickets, certificates and contracts with the details filled in
  • A printable version of a page of your app

For developers: one request

The same thing from your own code. It is a plain HTTP request, so it works from any language. Create a free account to get an access key.

Questions people ask

How do I convert HTML to PDF?

Send the HTML to CurlShot in the html field of a POST request and add format=pdf. The answer is the PDF file.

Do backgrounds and colors print?

Yes. Background colors and images are printed unless you switch them off with pdf_print_background=false, for a document that saves ink.

Can I control page breaks?

Yes, with normal CSS. Rules such as break-before, break-after and break-inside work as they do when a browser prints.

Can the whole document be one long page?

Yes. pdf_fit_one_page puts everything on a single tall page with no breaks.

Take as many screenshots as you need

A free account gives you 100 screenshots every month and keeps them in one place. No card needed.