Generation API & Scraper
The Generation API creates PDFs, social/OG images and charts on the fly and returns them as clean JSON (base64 or a download token).
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
The primary pdf_render endpoint returns a rendered PDF with filename, content type, byte size and a page hint, and the set also covers PDF from HTML or a URL, OG and template images, charts of many types and batch rendering. It is built for products that need server-side document and image generation without running a headless-browser render farm. One ReefAPI key, one shared credit pool, the standard envelope.
What comes back, and what gets rejected
Every action here is deterministic: the same input renders the same bytes. That also means the input checks are strict rather than forgiving, so knowing which mistakes are rejected outright saves a debugging session. All figures measured on 2026-08-27.
| Action | What you get back | Measured |
|---|---|---|
| pdf_render, pdf_from_html | file{file_b64, bytes, content_type, filename, delivery} | The built-in invoice template rendered to 9,075 bytes, delivery 'inline' |
| og_image | 1200x630 PNG by default, width and height overridable to 4000 | og_basic with a title and subtitle = 15,605 bytes |
| chart | PNG or SVG from a Chart.js-shaped spec, 8 chart types only | type 'violin' returned INVALID_PARAM listing bar, horizontal_bar, line, area, pie, doughnut, scatter, radar |
| barcode | Check digit computed or validated, never silently corrected | 5901234123456 returned INVALID_PARAM with detail.valid_code 5901234123457 |
| qr | png_base64 plus version, designator, modules and is_micro | A short URL at error correction m = version 2, designator 2-M, 25 modules |
| vcard, ical | Raw file text plus a data_uri, and a QR of it if as_qr is set | vCard 3.0 = 134 bytes, field_count 4; iCal uid is [email protected] |
| Remote images or CSS | Blocked at render unless the host is in allow_hosts | A PDF referencing one remote image returned INVALID_PARAM naming the blocked URL |
| validate_html | Lints without rendering, flags what the renderer will block | valid false, remote_resources listing both blocked URLs, tags_open 3 vs tags_close 1 |
| batch, batch_pdf, batch_image | Up to 50 small assets or 20 documents, per-item errors | 3 items returned count 3, ok_count 2, the bad barcode carrying its own error |
| template_list | The complete set of built-ins with a data_contract for each | 4 PDF templates, 4 image templates, and no stored-template CRUD |
code_image language auto-detection is unreliable, so pass `language` explicitly. Left to guess, a two-line Python function was labelled 'Tera Term macro' and a one-line SQL SELECT was labelled 'Text only'. Passing language 'python' for the same snippet returned language 'Python' and a correctly highlighted 7,095-byte PNG.
Real request and response JSON
Captured from the indexed primary action, pdf_render, on .
{
"method": "POST",
"url": "https://api.reefapi.com/generate/v1/pdf_render",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"template_name": "invoice",
"data": {
"company": {
"name": "Acme"
},
"items": [
{
"description": "Widget",
"qty": 2,
"unit_price": 9.5
}
],
"subtotal": 19,
"total": 19
}
}
}{
"ok": true,
"meta": {
"api": "generate",
"endpoint": "pdf_render",
"mode": "live",
"latency_ms": 1384.7,
"record_count": 1,
"bytes": 9074,
"cache_hit": false
},
"data": {
"file": {
"filename": "invoice.pdf",
"format": "pdf",
"content_type": "application/pdf",
"bytes": 9074,
"source": "template",
"pages_hint": null,
"file_b64": "JVBERi0xLjcKJfCflqQKNSAwIG9iago8PC9GaWx0ZXIgL0ZsYXRlRGVjb2RlL0xlbmd0aCA4MDY+PgpzdHJlYW0KeNqtV8uO0zAU3ecr8gPjuU/bVxqNBOIlJEBABQLEYigzbOgCWPD7XCdt3g20g6LWaZycc3yPfZxiDX5coH9lwZCzpSj1dlf9qCAkbXq7k+Zyf1w+wAD1t19+Z7YMbH6ngeZM5YRQo9VvnlZY/65iDpJIBGsyDplz4ljvKiYJqJJFhte/V2+r136cyLEMtquE1J/lrPwfSJbBdpWKBWGK/4FiCWpXJScmyiz/QgHCyMmRm5b9hMFZpVDQ2A5NATQy88SO/vqZHMtgYzvuTbIMNrTj3hRLUGM7/kqBrb9+EiFl8RPqqmQxZPX5IDWLhsRGWvRHDGY50vDy6eiLMCPxc/TLm7+X5ue36uGmwkN29NMJwWUkRNF6s6suX3589Oj9q5piiDECxnpzV326AiC5Bm8kNo1C+ytfw+d687x6vDkyqimtkI+OAHNtPtc4WhzTQse3bRgY28bahppm30etFhqJELQIuRRAEmhRo+CXcF4AC+5/Rq0RUxAAl99Ieffm",
"delivery": "inline"
}
}
}What the Generation API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| pdf_render | Render a PDF from inline HTML/CSS (Jinja2) or a built-in template_name + data (invoice/receipt/certificate/report). WeasyPrint, fonts pinned, network-off. Output: inline base64 (≤8MB) or one-time download token. | Platform and DevOps teams call pdf_render to render a PDF from inline HTML/CSS (Jinja2) or a built-in template_name + data (invoice/receip…. | html, template_name, data, paper, filename, ... |
| pdf_from_html | Shortcut for rendering inline HTML directly to PDF — the same WeasyPrint engine as pdf_render; `html` is required. | Security and supply-chain teams call pdf_from_html to get shortcut for rendering inline HTML directly to PDF. | html, data, paper, filename, allow_hosts |
| pdf_from_url | Render a built-in or inline template to PDF, populating it with data fetched live from a JSON URL you supply. Useful when your invoice or report data lives at a public API endpoint — no manual copy-paste needed. | Developer-tool builders call pdf_from_url to render a built-in or inline template to PDF, populating it with data fetched live from a JSON…. | data_url, template_name, html, data_path, paper, ... |
| og_image | Render a social / Open Graph card image (1200×630 default) from a built-in template or an inline layout spec. Supports automatic text-wrap and font scaling for long titles, colour gradients and badge overlays. | AI-agent developers call og_image to render a social / Open Graph card image (1200×630 default) from a built-in template or an inl…. | template_name, layout, vars, width, height, ... |
| image_from_template | Alias of og_image (explicit Bannerbear 'create image from template' naming). template_name + vars → PNG. | Platform and DevOps teams call image_from_template to get alias of og_image (explicit Bannerbear 'create image from template' naming). | template_name, vars, width, height, format, ... |
| image_from_url | Render an image template with `vars` fetched from a JSON URL (proxy, SSRF-validated). Data-driven banner generation. | Security and supply-chain teams call image_from_url to render an image template with `vars` fetched from a JSON URL (proxy, SSRF-validated). | data_url, template_name, layout, data_path, width, ... |
| chart | Render a chart from a Chart.js-style spec — returns a PNG or SVG image. Supported chart types: bar, horizontal_bar, line, area, pie, doughnut, scatter and radar. Powered by a matplotlib backend. | Developer-tool builders call chart to render a chart from a Chart.js-style spec. | spec, format, filename |
| chart_types | List all supported chart types with a description of each. No input required. | AI-agent developers call chart_types to list all supported chart types with a description of each. | none |
| batch_pdf | Render up to 20 PDFs in one call. `jobs` = array of pdf_render param objects. | Platform and DevOps teams call batch_pdf to render up to 20 PDFs in one call. | jobs |
| batch_image | Render up to 20 images in one call. `jobs` = array of og_image param objects. | Security and supply-chain teams call batch_image to render up to 20 images in one call. | jobs |
| template_list | List built-in templates (PDF + image) with their data contracts. Stateless — there is NO stored-template management (create/upload/delete out of scope). | Developer-tool builders call template_list to list built-in templates (PDF + image) with their data contracts. | none |
| validate_html | Lint HTML/CSS for the PDF path WITHOUT rendering: flags remote resources that the SSRF-safe renderer will block, size, and tag-balance hints. Deterministic. | AI-agent developers call validate_html to get lint HTML/CSS for the PDF path WITHOUT rendering. | html |
| health | Renderer diagnostics — which backends (WeasyPrint/Pillow/matplotlib) are loadable and their versions. No input. | Platform and DevOps teams call health to get renderer diagnostics. | none |
| qr | Generate a QR code (PNG or SVG) with custom fg/bg color, error-correction, and an OPTIONAL center logo fetched from logo_url (SSRF-guarded, via proxy). Use error_correction=h when embedding a logo so it stays scannable. | Security and supply-chain teams call qr to generate a QR code (PNG or SVG) with custom fg/bg color, error-correction, and an OPTIONAL ce…. | data, format, error_correction, scale, border, ... |
| barcode | Generate a 1D barcode IMAGE (PNG or SVG) from data: EAN-13/8, UPC-A, Code-128, Code-39, ISBN-10/13, ITF, GS1-128, JAN, PZN, Codabar. Check digits are validated — a wrong EAN/UPC/ISBN check digit returns a structured error, not a silent fix. | Developer-tool builders call barcode to generate a 1D barcode IMAGE (PNG or SVG) from data. | data, type, format, show_text, module_height, ... |
| code_image | Render a syntax-highlighted code snippet as a PNG with a carbon/ray.so-style window frame. 500+ languages (Pygments), 40+ themes, optional line numbers. | AI-agent developers call code_image to render a syntax-highlighted code snippet as a PNG with a carbon/ray.so-style window frame. | code, language, theme, window_style, line_numbers, ... |
| favicon | Turn one source image into a complete favicon bundle: multi-resolution favicon.ico, a named PNG set (16→512 incl. apple-touch-icon + android-chrome), site.webmanifest, and the ready-to-paste <head> <link> snippet. Source from image_url (SSRF-guarded) or a base64 upload. | Platform and DevOps teams call favicon to turn one source image into a complete favicon bundle. | image_url, image_base64 |
| vcard | Build a vCard (.vcf) contact file from contact fields (vCard 3.0 or 4.0). Returns the raw.vcf text + a base64 data-URI you can download or encode into a QR. | Security and supply-chain teams call vcard to build a vCard (.vcf) contact file from contact fields (vCard 3.0 or 4.0). | full_name, first_name, last_name, organization, title, ... |
| ical | Build an iCalendar (.ics) event file from event fields (RFC 5545). Supports timed or all-day events, end-time or duration, location, description, organizer. Returns the raw.ics + a base64 data-URI. | Developer-tool builders call ical to build an iCalendar (.ics) event file from event fields (RFC 5545). | summary, start, end, duration_minutes, location, ... |
| wifi | Generate a WiFi-join QR code (PNG/SVG) from network credentials — scan to connect, no typing. Encodes the standard WIFI: payload (WPA/WEP/open, hidden networks). | AI-agent developers call wifi to generate a WiFi-join QR code (PNG/SVG) from network credentials. | ssid, password, encryption, hidden, format, ... |
| batch | Generate up to 50 small assets in one request. Items run independently — a bad item yields its own error entry, never fails the batch. NOTE: items that fetch a remote logo_url/image_url ARE supported and SSRF-guarded. | Platform and DevOps teams call batch to generate up to 50 small assets in one request. | items |
Call pdf_render from your stack
curl -X POST https://api.reefapi.com/generate/v1/pdf_render \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"template_name":"invoice","data":{"company":{"name":"Acme"},"items":[{"description":"Widget","qty":2,"unit_price":9.5}],"subtotal":19,"total":19}}'import requests
r = requests.post(
"https://api.reefapi.com/generate/v1/pdf_render",
headers={"x-api-key": REEF_KEY},
json={
"template_name": "invoice",
"data": {
"company": {
"name": "Acme"
},
"items": [
{
"description": "Widget",
"qty": 2,
"unit_price": 9.5
}
],
"subtotal": 19,
"total": 19
}
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/generate/v1/pdf_render", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"template_name": "invoice",
"data": {
"company": {
"name": "Acme"
},
"items": [
{
"description": "Widget",
"qty": 2,
"unit_price": 9.5
}
],
"subtotal": 19,
"total": 19
}
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.generate.pdf_render with {"template_name":"invoice","data":{"company":{"name":"Acme"},"items":[{"description":"Widget","qty":2,"unit_price":9.5}],"subtotal":19,"total":19}}.Who uses this API and why
- SaaS products call pdf_from_html to turn invoices, reports and receipts into downloadable PDFs.
- Marketing tools use og_image and image_from_template to auto-generate share images at scale.
- Dashboards use chart to render server-side charts for emails and PDFs where JS cannot run.
Questions developers ask before integrating
Is this a text or AI generation endpoint?
No. Despite the name, nothing here is model-backed and no prompt is involved. It renders files from structured input: HTML and template data to PDF, a card spec to PNG, a data series to a chart, a string to a QR or barcode, contact fields to .vcf and event fields to .ics. The same input renders the same bytes every time, and a health call reports the concrete renderers in use with their versions.
How does the file reach me?
Base64 in the response body. The PDF and image actions wrap it in a file object carrying file_b64, bytes, content_type, filename and a delivery field that read 'inline' on every render measured. QR, barcode, code_image and wifi return png_base64 plus a ready-to-use data_uri instead. vCard and iCal return the raw file text as well, so you can inspect a .vcf or .ics without decoding anything.
What happens if my EAN or UPC check digit is wrong?
It is rejected with the correct code in the error, not silently fixed. Sending 5901234123456 as an ean13 returned INVALID_PARAM with the message that the last digit is a computed checksum and detail.valid_code set to 5901234123457. Sending too few digits fails differently, with a message stating EAN must have 12 digits and how many arrived. Supply the 12 data digits and let the engine compute the thirteenth if you would rather not do the arithmetic.
Can my PDF or card pull in a logo from my CDN?
Only if you allow that host explicitly. By default the renderer runs with no outbound network at all, and HTML referencing a remote image returned INVALID_PARAM naming the blocked URL and suggesting a data: URI. Pass allow_hosts with a comma-separated list of https hosts to open specific ones. For a single logo, embedding it as a data: URI is usually simpler and makes the render fully reproducible. Run validate_html first if you want the list of resources that would be blocked before you spend a render.
Can I upload and store my own templates?
No, and that is deliberate. The engine is stateless: there is no create, upload, list-mine or delete. template_list returns the four built-in PDF templates (invoice, receipt, certificate, report) and the four card layouts (og_basic, og_article, og_quote, og_product), each with a data_contract naming the exact keys it expects. To go beyond them, send inline `html` for PDFs or an inline `layout` object for images on each request. Your template lives in your repo, not in ours.
What does validate_html tell me that a failed render would not?
It tells you before you spend the render, and it separates two different problems. Linting a small snippet returned valid false, a remote_resources array with both offending URLs, an issues array explaining that each will be blocked by the renderer, and tags_open 3 against tags_close 1. Note that self-closing tags count toward tags_open, so a mismatch there is a hint to check your markup rather than proof of a bug.
One item in my batch is broken. Does the whole call fail?
No. Items run independently and a bad one produces its own error entry. A three-item batch with a valid QR, an invalid barcode and a valid wifi code returned ok:true at the top with count 3 and ok_count 2, the barcode row carrying an inline INVALID_PARAM. batch takes up to 50 small assets across qr, barcode, code_image, favicon, vcard, ical and wifi; batch_pdf and batch_image take up to 20 documents each. Always read ok_count.
Why does a QR response report a version and a module count?
Because they decide how large the code must be printed to stay scannable. A short URL at error correction m came back as version 2, designator 2-M and 25 modules across. More data or a higher error-correction level pushes the version up and the modules with it. If you are embedding a center logo, use error_correction 'h' and keep logo_size at or below 0.25: the parameter accepts up to 0.30, and past 0.25 the code can stop scanning even at the highest recovery level.
What is the Generation API?
Generation API is a ReefAPI endpoint group for generation It returns live JSON through POST requests under /generate/v1.
Is the Generation API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. Generation calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Generation login or account?
No login to Generation is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Generation data?
The page example is captured from a live pdf_render call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Generation API use?
Generation actions currently cost 1-4 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Generation from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call generate actions with the same key, credit pool and JSON envelope used by normal REST requests.