API Reference
POST your HTML, get a pixel-perfect PDF back. Built on Chromium — every CSS property, custom font, and image renders exactly as it does in Chrome.
Quickstart
Get your first PDF in under 60 seconds:
1. Create a free account — your API key is generated instantly.
2. Make a POST request with your HTML:
curl -X POST https://api.renderlyapi.com/v1/pdf/from-html \
-H "Authorization: Bearer rly_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"html":"<h1 style=\"font-family:sans-serif\">Hello!</h1>"}' \
--output hello.pdfYou'll get a PDF file back immediately. That's it.
Authentication
All API requests must include your API key in the Authorization header:
Authorization: Bearer rly_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxYou can manage your API keys from the dashboard. Keys start with rly_live_.
POST /v1/pdf/from-html
Convert an HTML string to a PDF. The most common endpoint.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| html | string | ✓ required | Full HTML string to render. Can include inline CSS, external fonts, images. |
| format | string | optional | A4LetterLegal — defaults to A4 |
| landscape | boolean | optional | Rotate to landscape. Default false |
| margin | object | optional | Page margins. Keys: toprightbottomleft — values like "1cm", "20px" |
| scale | number | optional | Viewport scale factor 0.1–2.0. Default 1 |
| print_background | boolean | optional | Include CSS backgrounds. Default true |
| wait_for | string | optional | loaddomcontentloadednetworkidle0networkidle2 |
Example
{
"html": "<html><body style='font-family:sans-serif; padding:40px'><h1>Invoice #001</h1><p>Amount: €500</p></body></html>",
"format": "A4",
"margin": { "top": "1cm", "right": "1cm", "bottom": "1cm", "left": "1cm" }
}Binary PDF data in response bodyPOST /v1/pdf/from-url
Navigate to a URL and capture it as a PDF. Useful for generating PDFs from existing web pages.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | ✓ required | Publicly accessible URL to capture. Must include https:// |
| format | string | optional | Same as from-html. Default A4 |
| landscape | boolean | optional | Default false |
| margin | object | optional | Page margins |
| wait_for | string | optional | Wait condition. Default networkidle2 |
Example
{
"url": "https://example.com/report",
"format": "A4",
"landscape": false,
"wait_for": "networkidle2"
}Binary PDF data in response bodyGET /v1/usage
Returns your current period usage and 6-month history.
Response
{
"plan": "free",
"period": "2026-05",
"docs_rendered": 12,
"docs_limit": 50,
"docs_remaining": 38,
"reset_date": "2026-06-01",
"history": [
{ "period": "2026-05", "docs_rendered": 12 },
{ "period": "2026-04", "docs_rendered": 31 }
]
}PDF options reference
| Option | Values | Default |
|---|---|---|
| format | A4A3A5LetterLegalTabloid | A4 |
| landscape | true / false | false |
| margin.top | CSS length (e.g. "1cm", "20px", "0") | "0" |
| margin.right | CSS length | "0" |
| margin.bottom | CSS length | "0" |
| margin.left | CSS length | "0" |
| scale | 0.1 – 2.0 | 1 |
| print_background | true / false | true |
| wait_for | loaddomcontentloadednetworkidle0networkidle2 | load |
Errors
All errors follow the same shape:
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key."
}
}| HTTP status | Code | Meaning |
|---|---|---|
| 400 | invalid_input | Missing required field or bad value |
| 401 | unauthorized | Missing, invalid, or revoked API key |
| 429 | rate_limited | Too many requests — slow down |
| 402 | quota_exceeded | Monthly PDF limit reached for your plan |
| 500 | internal_error | Something went wrong on our end |
Rate limits
Requests are rate-limited per API key to prevent abuse. When you exceed the limit you'll receive a 429 response. Limits are:
- 60 requests per minute per API key
- Monthly PDF limits depend on your plan (see below)
Plans & limits
| Plan | PDFs / month | Max HTML size | Price |
|---|---|---|---|
| Free | 50 | 5 MB | €0 |
| Starter | 500 | 20 MB | €19/mo |
| Pro | 2,000 | 50 MB | €49/mo |
| Scale | 10,000 | 100 MB | €99/mo |
Example — Invoice PDF
const res = await fetch('https://api.renderlyapi.com/v1/pdf/from-html', {
method: 'POST',
headers: {
'Authorization': 'Bearer rly_live_YOUR_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
html: `
<html>
<head>
<style>
body { font-family: 'Helvetica Neue', sans-serif; padding: 48px; color: #111; }
h1 { font-size: 28px; margin-bottom: 4px; }
.meta { color: #888; font-size: 14px; margin-bottom: 32px; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 10px 12px; text-align: left; border-bottom: 1px solid #eee; }
th { font-size: 12px; text-transform: uppercase; color: #888; }
.total { font-weight: 700; font-size: 18px; }
</style>
</head>
<body>
<h1>Invoice #001</h1>
<p class="meta">Acme Corp · May 28, 2026</p>
<table>
<tr><th>Item</th><th>Qty</th><th>Price</th></tr>
<tr><td>API Platform License</td><td>1</td><td>€1,200.00</td></tr>
<tr><td>Support Package</td><td>1</td><td>€300.00</td></tr>
<tr><td class="total">Total</td><td></td><td class="total">€1,500.00</td></tr>
</table>
</body>
</html>
`,
format: 'A4',
margin: { top: '1cm', right: '1cm', bottom: '1cm', left: '1cm' },
}),
});
const buffer = await res.arrayBuffer();
fs.writeFileSync('invoice.pdf', Buffer.from(buffer));cURL
curl -X POST https://api.renderlyapi.com/v1/pdf/from-html \
-H "Authorization: Bearer rly_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"html":"<h1>Hello Renderly</h1>","format":"A4"}' \
--output document.pdfNode.js
// Works with node-fetch, undici, or the built-in fetch (Node 18+)
import fs from 'fs';
async function renderPDF(html) {
const res = await fetch('https://api.renderlyapi.com/v1/pdf/from-html', {
method: 'POST',
headers: {
Authorization: 'Bearer rly_live_YOUR_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ html, format: 'A4' }),
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error.message);
}
const buffer = await res.arrayBuffer();
fs.writeFileSync('output.pdf', Buffer.from(buffer));
}
await renderPDF('<h1>My document</h1>');Python
import requests
def render_pdf(html: str, output_path: str = "output.pdf"):
res = requests.post(
"https://api.renderlyapi.com/v1/pdf/from-html",
headers={
"Authorization": "Bearer rly_live_YOUR_KEY",
"Content-Type": "application/json",
},
json={"html": html, "format": "A4"},
)
res.raise_for_status()
with open(output_path, "wb") as f:
f.write(res.content)
render_pdf("<h1>Hello from Python!</h1>")