Last updated: . Every code sample on this page was run against the live API with the sandbox key on that date.
Short answer: requests.post("https://rendlet.com/v1/pdf", headers={"Authorization": "Bearer KEY"}, json={"html": html}) returns the PDF bytes in r.content. Write them to a file or return them from your view. Rendering happens on Rendlet's side with headless Chromium, so there are no system packages to install on your server.
The public sandbox key needs no signup (5 renders a day per network, 1 page, up to 50 KB, faint watermark).
# Works as-is with the public sandbox key. With your own key: export RENDLET_API_KEY=YOUR_API_KEY
curl -X POST https://rendlet.com/v1/pdf \
-H "Authorization: Bearer ${RENDLET_API_KEY:-sandbox}" \
-H "Content-Type: application/json" \
-d '{"html":"<h1>Hello</h1><p>Rendered by Rendlet.</p>","options":{"format":"A4","margin":"15mm"}}' \
-o hello.pdf
html_to_pdf() helperInstall requests (pip install requests), save as render.py and run python render.py. It builds a small report table from data and saves report.pdf. Output when we ran it: saved report.pdf (1 page, 17052 bytes); 3 renders left.
# Python 3 + requests (pip install requests). Save as render.py and run: python render.py
# Uses the public sandbox key unless you set RENDLET_API_KEY=YOUR_API_KEY
import os
import requests
API_KEY = os.environ.get("RENDLET_API_KEY", "sandbox")
def html_to_pdf(html, options=None):
r = requests.post(
"https://rendlet.com/v1/pdf",
headers={"Authorization": "Bearer " + API_KEY},
json={"html": html, "options": options or {"format": "A4", "margin": "15mm"}},
timeout=60,
)
if not r.ok:
# Errors are JSON, e.g. {"error": "quota_exceeded", ...}
raise RuntimeError(f"Rendlet {r.status_code}: {r.text}")
return r.content, r.headers.get("X-Pages"), r.headers.get("X-Quota-Remaining")
report = {"title": "Weekly sales", "rows": [("North", 1200), ("South", 950)]}
rows = "".join(f"<tr><td>{name}</td><td>{amount:,}</td></tr>" for name, amount in report["rows"])
html = f"""<!doctype html>
<html><body style="font-family:sans-serif;padding:24px">
<h1 style="color:#1f4e79">{report['title']}</h1>
<table border="1" cellpadding="6" style="border-collapse:collapse">
<tr><th>Region</th><th>Sales (USD)</th></tr>{rows}
</table>
</body></html>"""
pdf, pages, remaining = html_to_pdf(html)
with open("report.pdf", "wb") as f:
f.write(pdf)
print(f"saved report.pdf ({pages} page, {len(pdf)} bytes); {remaining} renders left")
In production, render your HTML with the template engine you already use (Jinja2, Django templates) so values are escaped, then pass the string to html_to_pdf().
| Field | Values |
|---|---|
options.format | A4, Letter, Legal, A3, A5 |
options.landscape | True / False |
options.margin | CSS length, e.g. "15mm" or "0" |
options.printBackground | True / False |
filename | Name used in the Content-Disposition header |
response | "binary" (default) or "base64": JSON with a base64 field (decode with base64.b64decode) |
For HTML input, JavaScript in the page is not run, and only data: URIs and public https:// assets load. Inline your CSS or link it over https. Simplified Chinese works out of the box (Noto Sans SC is bundled).
Successful renders return X-Pages, X-Plan, X-Quota-Limit and X-Quota-Remaining. Errors are JSON like {"error":"...","message":"..."}: 400 bad request, 401 missing key, 403 invalid key, 413 HTML too large or too many pages, 429 quota exceeded, 500 render failed.
Return the bytes with Content-Type: application/pdf (and Content-Disposition: attachment; filename=... if you want a download), or save them to object storage. Keep the API key in an environment variable on the server.
| Sandbox | Free | Starter | Pro | Scale | |
|---|---|---|---|---|---|
| Price | $0 | $0 | $7/mo | $19/mo | $59/mo |
| Documents | 5 / day / network | 100 / month | 1,000 / month | 5,000 / month | 25,000 / month |
| Requests per minute | 3 | 10 | 30 | 60 | 120 |
| Pages per document | 1 | 10 | 50 | 200 | 500 |
| HTML size | 50 KB | 1 MB | 2 MB | 2 MB | 2 MB |
Every plan has a hard monthly cap: at the cap the API returns 429 with an upgrade_url, and you are never billed for overage. Failed renders don't count. Source: docs.
wkhtmltopdf's GitHub repository was archived in January 2023; see Rendlet vs wkhtmltopdf for a migration example. If your pages need JavaScript or a login to render, a self-hosted browser is the better fit: see Rendlet vs Puppeteer.