Developer API
HTML to PDF API
HTML-to-PDF is the workhorse endpoint in most invoice, report, and receipt pipelines. It's also the most overpriced category in the developer-PDF market — DocRaptor charges $0.12/doc after a $15/month minimum, PDFShift $0.18/doc overage on a $9/month base, and the self-hosted Puppeteer path eats engineering time forever.
PennyPDF's /v1/html-to-pdf runs headless Chromium with print-CSS media queries enabled. Pass an HTML string, a raw URL, or a HTML+CSS payload; receive the rendered PDF back in ~1–3 seconds for a typical invoice. 1 coin per render. That's 4 cents at the Saver pack, 3 cents at the Pro pack.
The endpoint supports page size (A4, Letter, custom), margins, header/footer templates (also HTML), landscape orientation, wait-for-selector (so your JS-rendered dashboard renders fully before we snapshot), and bundled webfont inlining. Everything you'd expect from Puppeteer, behind a bearer token.
Copy, paste, ship
Same bearer-token auth across every endpoint. Set PENNYPDF_API_KEY in your environment first.
curl -X POST https://api.pennypdf.com/v1/html-to-pdf \
-H "Authorization: Bearer $PENNYPDF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<h1>Invoice INV-1042</h1><p>Amount due: $1,200</p>",
"page_size": "Letter",
"margins": {"top": "1in", "bottom": "1in"}
}' \
-o invoice.pdfimport os, requests
r = requests.post(
"https://api.pennypdf.com/v1/html-to-pdf",
headers={
"Authorization": f"Bearer {os.environ['PENNYPDF_API_KEY']}",
"Content-Type": "application/json",
},
json={
"url": "https://reports.example.com/invoice/1042?render=true",
"wait_for_selector": "#invoice-ready",
"page_size": "A4",
},
timeout=30,
)
r.raise_for_status()
open("invoice.pdf", "wb").write(r.content)PennyPDF vs DocRaptor
| PennyPDF | DocRaptor | |
|---|---|---|
| Price per doc | 1 coin (~$0.04) | $0.12/doc overage |
| Monthly minimum | $0 | $15/mo for 125 docs |
| Test-mode docs | 10 welcome coins (3 free tests) | Unlimited, but watermarked |
| PDF engine | Chromium (print CSS) | PrinceXML |
| Output quality for print | Very good | Best-in-class for typography |
| Pay-as-you-go | Yes, always | No |
How it works
- 1Grab an API key at /dashboard/api.
- 2POST {html} or {url} to /v1/html-to-pdf with your page-size and margin preferences.
- 3Receive the PDF synchronously in the response body — no job polling for standard renders.
Frequently asked
How does quality compare to DocRaptor's PrinceXML?+
For most invoices, reports, and statements, the output is indistinguishable. PrinceXML has an edge on complex typography (hyphenation, ligatures, orphans/widows control) because it's a print-first engine. Chromium wins on modern CSS (Grid, Flexbox, custom properties) and JavaScript-rendered content. Pick based on your primary use case.
Does it execute JavaScript?+
Yes. Full Chromium, so React/Vue/Svelte-rendered pages work. Use `wait_for_selector` or `wait_for_ms` to control when the snapshot happens — without it, we snapshot at the DOMContentLoaded event, which misses async data fetches.
What's the latency?+
Inline HTML: 90th percentile 1.1 s for a 5-page invoice. URL-based render: 2–4 s depending on how many assets the page loads. For anything over 5 s expected time, use the async variant (POST /v1/jobs/html-to-pdf) so you don't tie up a connection.
How do headers and footers work?+
Pass `header_template` and `footer_template` as HTML strings. They render on every page. Standard Chromium template variables work: `<span class="pageNumber"></span>`, `<span class="totalPages"></span>`, `<span class="date"></span>`, `<span class="title"></span>`.
Rate limits?+
200 requests/minute baseline, burst to 400. For bulk document generation (invoicing runs, end-of-month reports), the async jobs endpoint runs without the per-minute cap — coins are the only limit there.
Can I use my own fonts?+
Yes. Reference them via @font-face in your HTML with absolute URLs — Chromium will fetch them during render. For offline-only fonts, base64-encode them into the CSS to avoid the fetch.
Why PennyPDF
- No subscription. Ever.
- Coins never expire — use them in 5 years.
- Client-side processing for 14 of 22 tools.
- No watermarks at any tier.
- Per-operation pricing, shown before you click.
- Same coins for web + public API.