Your HTML.
Print-ready PDF.
One request.
Send HTML, upload a file, or point us at a URL — get back a PDF that looks exactly like the page. Every font, every language, every page break where you put it. Built for invoices that have to be right the first time, at 4am, on the hundred-thousandth one.
format and margin. There are 45
more, and the key lasts 24 hours.
Full console, all 47 options →
300 renders free
Four ways in. One result.
Whichever one fits the code you already have — or no code at all. Same options, same output.
An HTML string
Template it in your own code and post it as JSON. The usual choice when the document is generated per request — an invoice, a report, a ticket.
"source": { "html": "<h1>Invoice</h1>" }
An uploaded file
Post the file itself as multipart — .html or
.htm. No escaping a 400 KB template into a JSON string,
and no shell quoting to get wrong.
A page that links to css/style.css, images or fonts needs
them too: send a .zip of the folder and every relative path
still resolves. index.html is the entry point, otherwise the
shallowest page. Or send the files with a paths array, which
renders identically. Drop one into the box at the top of this page.
curl -F "file=@invoice.html" \ -F 'options={"format":"A4"}' # a folder, with its css/ and fonts/ curl -F "file=@invoice.zip"
A live URL
Point us at a page and we load it the way a browser would, so its own stylesheets,
images and fonts resolve. For pages behind a bot wall, add
via_crawler and we fetch it through our crawling infrastructure —
proxies, stealth browser, challenges solved.
"source": { "url": "https://…" }, "options": { "via_crawler": true }
No markup at all
Design the document by dragging boxes onto the page — text, images, tables, barcodes — then render it with your data. Every box you name becomes a field. Open the editor →
POST /templates/<id>/render "data": { "customer": "ACME GmbH" }
The four things that ruin a PDF
Each one is a support ticket you will get from somebody else's API. We fixed them before you hit them.
Every language, right the first time
Vietnamese, Chinese, Japanese, Korean, Thai, Arabic, Cyrillic and colour emoji come out as themselves — never tofu boxes, never the wrong accent. Send an invoice to any market without checking the output by hand.
Nothing prints half-drawn
Charts, web fonts and lazy images finish before the page is captured. You say what "ready" means — an element, a JS condition, network idle, or a delay — instead of hoping the renderer guessed right.
The page is the size you asked for
Ask for A5 landscape and you get A5 landscape — the dimensions, not just the orientation. Headers, footers, page numbers, margins and page ranges all behave the way print people expect.
Your HTML can't phone home
Sub-resources cannot reach loopback, private or cloud-metadata addresses. If your users author the templates, that matters more than it sounds.
Why you can trust the output
We would rather show you what is tested than tell you who else is buying.
19 documents that break renderers
The test suite renders a 400-row table, a 20-column spread, right-to-left text, shadow DOM, CSS filters, web fonts and forced page breaks — then compares the result against a second independent engine and fails if a single character moved.
E-invoices checked by the real validators
ZUGFeRD and Factur-X output is checked with the official EN 16931 validators — Mustangproject and KOSIT, the same tools your buyer's tax software uses — not against our own idea of the spec.
The SSRF test counts real requests
A test stands up an actual listener on a private address, points caller HTML at it, and fails if even one request arrives — plus a control request that must arrive, so an empty result can never come from a broken test.
It runs our own business
The same renderer produces the invoices that live Shopify stores send their customers, with real money and real tax authorities on the other end. If it breaks, it breaks for us first.
And when we cannot do something you asked for, you get an error that names the option — never a PDF that quietly came back without it. Failed renders are never billed.
Priced per render
Not per megabyte, not per feature. Every plan gets every option.
$5/mo
2,500 renders
$0.0020 each, plus 14,167 conversion pages.
3-day free trial — cancel before it ends and you pay nothing.
Start free trial →$9.99/mo
7,500 renders
$0.0013 each, plus 33,333 conversion pages.
3-day free trial — cancel before it ends and you pay nothing.
Start free trial →$29.99/mo
30,000 renders
$0.0010 each, plus 125,000 conversion pages.
3-day free trial — cancel before it ends and you pay nothing.
Start free trial →$99.99/mo
150,000 renders
$0.0007 each, plus 666,667 conversion pages.
3-day free trial — cancel before it ends and you pay nothing.
Start free trial →One subscription, not two. The same plan covers the HTML-to-PDF API and the document conversion and OCR tools. Renders and pages have separate allowances, so a busy month on the API never eats the quota you bought for conversions.
| Volume / month | SayPDF | PDFShift | DocRaptor | Api2Pdf |
|---|---|---|---|---|
| 2,500 renders | $5 | $24 | $149 | $12.50 |
| 7,500 renders | $9.99 | $99 | $399 | $37.50 |
| 30,000 renders | $29.99 | $149 | $1,000 | $150 |
| 150,000 renders | $99.99 | $499 | Quoted | $750 |
| Per render, at 150k | $0.0007 | $0.0020 | — | $0.005 |
Competitor prices are their own published list prices, re-checked 1 October 2026, taking the smallest tier that actually covers that volume — you cannot buy 7,500 renders from PDFShift, so that row is their 25,000 tier at $99. Api2Pdf is its flat $0.005 per PDF. DocRaptor's published ladder ends at 40,000 documents for $1,000, so 150,000 is quoted rather than listed and we will not invent a number for it. Please check them yourself before you decide; we would.
Plans renew monthly. One render is one call, whatever the page count and whatever finishing it asks for. OCR and scanned-document conversions are billed separately — see full pricing.
How it compares
| SayPDF | PDFShift | DocRaptor | |
|---|---|---|---|
| Renders like a browser | Yes | Yes | Own engine |
| Rendering options | 47 | 37 | 50 |
| CJK, Vietnamese, Arabic, Thai, Korean — fonts embedded | Measured yes | Not tested | Measured yes |
| Newer emoji, U+1F9FE 🧾 | Renders | Not tested | Empty box |
| ZUGFeRD / Factur-X e-invoice | Yes | No | No |
| PDF/A & PDF/UA | Yes | No | Add-on |
| Password protection | Yes | Yes | Yes |
| 30,000 renders / month | $29.99 | $149 | $1,000 |
| Free tier | First 300, one-off | 50 credits / month | 5 docs / month |
| An unwatermarked PDF before you sign up | Yes, above | Account first | Watermarked tests |
Prices and free
tiers as published on their own sites, re-checked 1 October 2026. Option counts are
counted, not quoted: PDFShift's from
their
OpenAPI document, DocRaptor's from their API reference, ours from the parameter
map in our own source. The font rows are a head-to-head render of one HTML document
through both APIs on 1 October 2026, compared with pdffonts and
pdftotext; PDFShift is marked not tested because its free tier needs an
account.
Check them before you decide — we would, and the
full comparison across nine other vendors says
where each one wins.
When this is the wrong choice
Four cases where we would tell you to buy something else. If none of them is you, the box at the top of this page settles it in about ten seconds.
You need print-publishing typography
Running headers, footnotes, cross-references, precise widow and orphan control — CSS paged media as the standard actually specifies it. That is DocRaptor and PrinceXML, and it is genuinely better at it than Chromium. We render like a browser, which is the right engine for invoices and reports and the wrong one for a book.
You need a vendor your procurement team recognises
If the purchase needs a signed DPA, a SOC 2 report, a security questionnaire returned in a week and a support contract with named hours, buy from a company with a compliance department. SayPDF is small. That is why it is cheap, and it is a real reason not to choose it.
You have the ops capacity to self-host
The renderer here is Gotenberg, which is open source and free. If you already run containers and would rather own the uptime than pay for it, run it yourself — you will not get a better deal from us than $0. You are paying here for the queue, the fonts, the font fallbacks, the retries and nobody being woken up.
Your HTML is not finished
No API renders a page whose layout is wrong; it renders the wrong layout very accurately. If the thing that keeps breaking is the document itself, the useful tool is a browser's print preview and an afternoon, not a subscription.
Still comparing? The ten-vendor table has each one's cheapest paid plan, free tier, billing unit and whether you can render before signing up, with the date each figure was checked.
Boring, on purpose
A document API is infrastructure. It should be the least interesting thing in your stack.
Fast, and steady
A typical invoice comes back in well under a second, and the tenth thousand takes as long as the first. The renderer is kept warm rather than started per request.
It tells you the truth
An option we cannot apply is a clear error naming that option — never a PDF that quietly came back missing what you asked for. Failed renders cost you nothing.
Two engines, one output
If the primary renderer is unavailable, a second one takes over automatically. Same engine family, same result — you get a PDF, not an incident.
Archive-grade output
PDF/A and PDF/UA when you need to file it or make it accessible, password protection and watermarks when you need to control it.
Everything print needs, on one endpoint
Forty-seven options, all documented, all included on every plan. Nobody hides page numbers behind an upgrade.
A German or French e-invoice, from the same call
Pass your CII XML and get back a PDF/A-3 with the invoice attached,
the right AFRelationship and the Factur-X XMP extension schema — a file a
German buyer's system will accept, not a PDF with an XML zipped next to it.
Profiles: MINIMUM, BASIC WL, BASIC, EN 16931, EXTENDED, XRECHNUNG. Germany's mandate starts 1 January 2027.
Live on every plan, including the free
one. E-invoice embedding, PDF/A, PDF/UA, password protection and watermarking need
no request and no add-on — pass the option and you get the file. If the PDF engine is ever
down the API answers 503 and names the option, rather than returning a PDF that
quietly lacks it.
{
"source": { "html": "<h1>Rechnung RE-2026-1001</h1>" },
"options": {
"facturx": {
"xml": "<rsm:CrossIndustryInvoice>…",
"conformance": "EN 16931"
}
}
}
→ PDF/A-3 · factur-x.xml embedded · XMP written
Questions people actually ask
Can I send a URL instead of HTML?
Yes — source: { "url": "https://…" }. The page loads from its own origin, so
relative stylesheets, images and links resolve the way they do in a browser. The URL has to
be publicly reachable; private and loopback addresses are refused.
My page draws a chart with JavaScript. Will it be in the PDF?
If you tell us to wait for it, yes. Use wait_for_selector,
wait_for with a JS expression, or a plain delay. We do not guess:
an engine that silently waits "long enough" is one that silently stops waiting long enough.
Do you store my HTML or the PDF?
The PDF is returned in the response body when you ask for it inline or as base64 — nothing
is kept. Hosted output (output: "url") is stored so the link works, and is
deleted on the retention schedule in our privacy policy.
What happens to page numbers and headers?
Nothing, unless you ask. There is no header or footer by default. Supply
header / footer HTML and use the pageNumber,
totalPages, date, title and url
classes.
Is a 400-row invoice table going to break?
It paginates, repeats the <thead> on every sheet and does not slice a row
in half. That behaviour is on by default and can be turned off with
print_css_defaults: false if you would rather own the print CSS yourself.
What exactly is "the first 300 renders free"?
A one-off grant on your account, not a monthly reset. Every page you render counts
against it until it runs out, then a plan takes over. The response tells you where you
stand: freePagesRemaining in the JSON body, or the
X-Free-Pages-Remaining header on a binary response. Failed renders are not
counted — if we could not produce the PDF, it does not come out of your grant.
How fast is it?
Chromium is kept warm, so a typical invoice comes back in a few hundred milliseconds rather than paying a browser launch on every call. Heavy documents, PDF/A conversion and e-invoice embedding take longer — they are doing more work.
Start rendering in 30 seconds
Your first 300 renders are on us — no credit card, no sales call. One POST and you have a PDF.