Formfeed turns a POST request into a pixel-perfect PDF — invoices, contracts, reports — rendered from versioned templates, validated before a single pixel draws.
curl -X POST https://api.formfeed.dev/v1/renders \
-H "Authorization: Bearer ff_test_5k...N2WP" \
-d '{
"template": "invoice-eu-vat@v4",
"data": { "invoice_no": "INV-2107", "total": "4180.00" }
}'
# 201 Created · 412ms
{ "id": "R-88241", "status": "rendered",
"pdf": "https://cdn.formfeed.dev/r/R-88241.pdf" }Templates are versioned. Your data is validated against the template's schema before rendering — bad payloads fail in milliseconds with a field-level error, not a broken PDF.
The PDF pipeline is always someone's side quest — until month-end, an auditor, or a Turkish character makes it the main one.
A pinned Chrome, a flaky container, and a retry loop — hundreds of lines of infrastructure to print an invoice.
The layout that survived every test meets a 47-line invoice with a credit note on the 31st, at volume.
"Send us the invoice as issued in March." If your template changed since, what do you regenerate it with?
The ß that rendered as a box, the RTL address, the currency symbol your system font didn't ship.
Templates, validation, environments, and a log you can take to an auditor.
Every render is traceable: payload, template version, timing, outcome. Replay any of them — including the failures — with one call.
Each template publishes a schema; bad payloads fail fast with field-level errors.
Separate keys, separate quotas, watermarked test renders. CI never touches production paper.
invoice-eu-vat@v4 renders the same page in March, in July, and in court. Ship v5 without rewriting history.
render.completed and render.failed to your endpoint; PDFs to our CDN or your bucket.
The template is the contract — your code only ever sends data.
Start from our invoice, contract, and report templates or bring your own layout. Every template publishes the schema its data must satisfy.
POST your JSON with a test key. Validation errors name the field; watermarked previews render in the console as you iterate.
Same endpoint, live key, clean paper. Webhooks confirm every render; the log keeps the receipts.
“We deleted four hundred lines of headless-browser babysitting the week we moved invoices over. Month-end just… renders now.”
“Contracts have to look identical in March and in court. Versioned templates mean the PDF we sent is the PDF we can prove we sent.”
Test mode is free forever. Live plans include renders, then meter at $9 per 1,000 — nothing ever drops at the line.
Build against the real API.
Your first paper in production.
Month-end at volume.
Under the hood it's a pinned, patched render farm with deterministic font resolution — but the difference is the contract around it: schema validation before render, snapshot tests on every template version, and a render log you can replay. The flaky part of headless PDF work was never Chrome; it was owning all of that yourself.
Templates bundle their fonts, so the ß, the ₺, and the RTL address render the same on every run. Number, date, and currency formatting follow the locale you pass per render — one template can invoice Berlin and Osaka.
Median 412ms, p95 780ms for a one-page invoice; long reports scale roughly per page. A cold template version adds about a second on its first render, then it's warm. The console shows your real numbers — those are ours.
By default: request payloads are deleted after the render completes, PDFs live on our CDN for 30 days, and the log keeps metadata (template, version, timing, outcome) for a year. On Scale you can point storage at your own bucket and set retention to zero on our side.
Yes — pick eu-central per key or per render on the Scale plan, and payloads never leave the region. We'll sign a DPA, and the subprocessor list is public and short.
Nothing dramatic. Renders keep flowing and meter at $9 per 1,000; you can set a hard cap or a spend alert if you'd rather be asked. Month-end invoices don't wait for a quota conversation.
A test key, one POST, and the invoice you've been dreading owning — rendered.
Test mode free forever · No card required