PDFOven
Tạo PDF và hình ảnh PNG từ HTML, Markdown, URL hoặc mẫu Handlebars; khóa API miễn phí với 100 lần kết xuất mỗi tháng.
Máy chủ MCP được lưu trữ
npx add-mcp 'https://pdfoven.com/mcp'Cài vào Claude Code, Codex, Cursor và nhiều công cụ khác
Tài liệu
API documentation
Base URL: https://pdfoven.com. All requests use JSON and an API key from your dashboard (free signup). The whole API is described in the OpenAPI 3.1 spec.
Quickstart
- Create a free account; your API key is ready right away and set it as
PDFOVEN_KEY. - Run this. It uses the built-in invoice template, so it works with no setup:
curl https://pdfoven.com/v1/pdf \
-H "Authorization: Bearer $PDFOVEN_KEY" \
-H "Content-Type: application/json" \
-d '{"template_id":"tpl_invoice","data":{"number":"INV-0001"}}' \
-o invoice.pdf
The response body is the PDF (Content-Type: application/pdf), with headers X-Render-Ms (render time) and X-Usage-Remaining (renders left within your plan limit this month). Past the limit you're in the 10% grace buffer: X-Usage-Grace-Remaining counts the renders left before HTTP 429, and X-Usage-Notice says you're in the buffer and suggests upgrading. Errors come back as JSON, described under Errors.
Authentication
Send your key as a bearer token: Authorization: Bearer po_live_…. The X-API-Key header also works.
POST /v1/pdf
Renders a PDF. Provide exactly one source:
html | An HTML string. Fragments are wrapped in a document with sensible base styles. |
|---|---|
markdown | A Markdown string (GitHub-flavored). |
url | A public http(s) URL to capture. |
template + data | An inline Handlebars template and the JSON to fill it with. |
template_id + data | A template saved in your dashboard, or a built-in template such as tpl_invoice. If data is omitted, its sample data is used. |
Optional fields:
css | Extra CSS appended to the document. |
|---|---|
options.format | A4 (default), Letter, Legal, A3, A5, Tabloid |
options.landscape | Boolean, default false. |
options.margin | Uniform margin such as "0.5in", "12mm" or "20px". |
options.print_background | Print background colors and images. Default true. |
options.header_template / footer_template | HTML for a repeating header/footer. Use <span class="pageNumber"></span> and <span class="totalPages"></span>. Requires a margin so it has room. |
options.scale | 0.1 – 2. |
wait_for_selector | Wait for a CSS selector before rendering, for pages that draw charts with JavaScript. |
timeout_ms | 1,000 – 60,000. Default 30,000. |
response | "binary" (default) returns the file. "base64" returns JSON { "data": "…", "content_type": "application/pdf", "bytes": 1234 }. |
filename | Sets the Content-Disposition filename. |
curl https://pdfoven.com/v1/pdf \
-H "Authorization: Bearer $PDFOVEN_KEY" \
-H "Content-Type: application/json" \
-d '{"html":"<h1>Hello, PDF</h1>","options":{"format":"Letter","margin":"0.5in"}}' \
--output hello.pdf
POST /v1/image
Takes the same sources as /v1/pdf and returns a PNG. Call /v1/image?type=jpeg for a JPEG instead. Image options in options: width, height, full_page, device_scale_factor (1–3) and quality (JPEG only).
For social share images, use a built-in 1200×630 card and send only the text: tpl_og_article, tpl_og_product or tpl_og_announcement. Long titles shrink to fit. See the fields under Built-in templates, or design one in the social image generator.
curl "https://pdfoven.com/v1/image" \
-H "Authorization: Bearer $PDFOVEN_KEY" \
-H "Content-Type: application/json" \
-d '{"template_id":"tpl_og_article","data":{"site":"acme.dev","title":"Launch day","author":"Ada"}}' \
--output og.png
POST /v1/screenshot
Screenshots a public web page. It's /v1/image with a url, plus options made for pages you don't control:
options.width / height | Viewport size in pixels. Default 1280 × 800. |
|---|---|
options.full_page | Capture the whole scrollable page. |
options.color_scheme | "light" (default) or "dark", for sites that follow the system theme. |
options.hide_selectors | CSS selectors to hide first, such as cookie banners and chat widgets. |
options.selector | Capture just the first element matching this selector. |
options.delay_ms | Wait 0–10,000 ms after loading, for animations. |
options.device_scale_factor | 2 for retina-sharp images. |
curl "https://pdfoven.com/v1/screenshot?type=jpeg" \
-H "Authorization: Bearer $PDFOVEN_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","options":{"width":1440,"full_page":true,"hide_selectors":["#cookie-banner"]}}' \
--output page.jpg
PDF tools
These endpoints work on PDFs you already have. Send each file as JSON, either {"base64": "…"} or {"url": "https://…"}, with "password" if it's protected. Or upload it as multipart/form-data: the PDF in a file field (files for merge), and the other parameters as fields of the same name or as one JSON payload field.
- Each call uses one render, except listing form fields, which is free. Failed calls don't count.
- Files can be up to 50 MB each and 60 MB together, and up to 5,000 pages.
- Results come back as the file, with
X-Page-Countand the usage headers."response": "base64"returns JSON with the file and the same details. Output is never password-protected. - Page selections look like
"1-3,5,8-".lastmeans the final page, and a range can run backwards ("last-1") to reverse the order.
POST /v1/pdf/merge
Joins 2–50 PDFs in the order given. Each file can take pages to pick and reorder its pages; one file with pages also works, for reordering a single PDF.
curl https://pdfoven.com/v1/pdf/merge \
-H "Authorization: Bearer $PDFOVEN_KEY" \
-F files=@cover.pdf -F files=@report.pdf \
-o merged.pdf
{
"files": [
{ "url": "https://example.com/cover.pdf" },
{ "base64": "JVBERi0x…", "pages": "2-last" }
],
"filename": "q3-report"
}
POST /v1/pdf/split
Send exactly one of:
pages | Extract these pages into one PDF, e.g. "1,3-4". |
ranges | One PDF per range, e.g. ["1-2","3-last"], returned as a zip. |
every | Split into parts of this many pages, returned as a zip. X-File-Count says how many. |
When ranges or every produces a single part, you get that PDF instead of a zip; check Content-Type. | |
curl https://pdfoven.com/v1/pdf/split \
-H "Authorization: Bearer $PDFOVEN_KEY" \
-F file=@statement.pdf -F every=1 \
-o pages.zip
POST /v1/pdf/compress
Makes a PDF smaller by recompressing and downscaling large photos, compressing uncompressed content and dropping unused data. Text and vector graphics stay sharp. level is low (closest to the original), medium (default) or high (smallest). remove_metadata also strips the title, author and XMP metadata.
The response headers X-Original-Bytes, X-Compressed-Bytes and X-Saved-Percent report the result. If the file can't be made smaller you get it back unchanged with X-Already-Optimized: true.
curl https://pdfoven.com/v1/pdf/compress \
-H "Authorization: Bearer $PDFOVEN_KEY" \
-F file=@scan.pdf -F level=high \
-o smaller.pdf
POST /v1/pdf/watermark
Stamps text (up to 5 lines, Latin characters) or an image (PNG or JPEG) on every page, or on pages.
position | center (default, diagonal), tile (repeated across the page), or a corner or edge: top-left, top-center, top-right, bottom-left, bottom-center, bottom-right. |
|---|---|
opacity | 0.01–1. Default 0.2 for text, 0.3 for images. |
color | Hex text color. Default #6b7280. |
rotation | Degrees. Center and tile follow the page diagonal unless set. |
font_size / scale | Text size in points, or a size multiplier (0.1–3) when the size is automatic. |
margin | Distance from the edge for corner positions, in points. Default 36. |
Rotated pages are handled, so the watermark always reads upright.
curl https://pdfoven.com/v1/pdf/watermark \
-H "Authorization: Bearer $PDFOVEN_KEY" \
-H "Content-Type: application/json" \
-d '{"file":{"url":"https://example.com/contract.pdf"},"text":"CONFIDENTIAL","position":"tile","opacity":0.12}' \
-o watermarked.pdf
Fill PDF forms
POST /v1/pdf/form/fields lists a form's fields: name, a readable label, type (text, checkbox, radio, dropdown, option_list …), current value, options, max_length and the pages it's on. It's free.
POST /v1/pdf/form/fill fills fields by name. Text takes strings or numbers, checkboxes take true / false, and radio and dropdown values must match an option (case doesn't matter). flatten: true makes the result read-only. A misspelled field name is an error that suggests the right one; send strict: false to skip unknown names instead.
curl https://pdfoven.com/v1/pdf/form/fill \
-H "Authorization: Bearer $PDFOVEN_KEY" \
-F file=@w9.pdf \
-F 'fields={"name":"Ada Lovelace","agree":true,"state":"OR"}' \
-F flatten=true \
-o filled.pdf
Templates
Templates are HTML with Handlebars placeholders, plus optional CSS and default page options. Create them in the dashboard with a live preview, or via the API. Markdown templates are also supported.
Built-in templates
Every account can render these without saving anything; they don't count toward your template limit. Send any subset of fields in data and the rest come from the sample data, so {"template_id":"tpl_invoice","data":{"number":"INV-2041"}} works as-is with a new key.
tpl_invoice | Clean invoice with line items, tax and totals. |
|---|---|
tpl_receipt | Compact payment receipt for e-commerce and SaaS. |
tpl_certificate | Landscape certificate of completion. |
tpl_report | Readable multi-page report written in Markdown. |
tpl_paystub | Earnings statement with hours, rates, deductions and net pay. |
tpl_packing_slip | Order packing slip with ship-to address, SKUs and quantities, no prices. |
tpl_og_article | Open Graph image for a blog post or page: site name, title, subtitle, author and date. Light or dark. Render with /v1/image (1200×630). Fields: site, eyebrow, title, subtitle, author, date, accent, dark. |
tpl_og_product | Product or listing card: brand, product name, tagline, price, a badge and a product image. Render with /v1/image (1200×630). Fields: brand, name, tagline, price, badge, accent. |
tpl_og_announcement | Launch or event announcement on a gradient: label, headline, detail line and a call to action. Render with /v1/image (1200×630). Fields: label, headline, detail, site, cta, color_from, color_to. |
To customize one, open it in the template editor as a starter and save your own copy.
Built-in helpers:
{{formatCurrency amount "EUR"}} | Formats money. Defaults to USD. |
|---|---|
{{formatNumber value 2}} | Fixed decimals. |
{{formatDate issued_at "medium"}} | short / medium / long / full. |
{{sum items "amount"}} | Sums a field across an array. |
{{lineTotal items "qty" "price"}} | Sum of qty × price across an array. |
{{multiply a b}}, {{add a b}} | Arithmetic. |
{{#if (eq status "paid")}} | Equality checks. |
{{upper text}} | Uppercase. |
GET /v1/templates
Lists your templates.
POST /v1/templates
{
"name": "Invoice",
"engine": "handlebars",
"content": "<h1>Invoice {{number}}</h1>",
"css": "h1 { color: #c8155f }",
"sample_data": { "number": "INV-1" },
"page_options": { "format": "Letter", "margin": "0.5in" }
}
GET /v1/usage
Returns your plan, limit and renders used this calendar month (UTC). grace_limit is the limit plus the 10% grace buffer every plan gets; once used passes limit, in_grace_buffer is true and notice suggests upgrading.
{ "plan": "starter", "period": "2026-10", "used": 2050, "limit": 2000, "grace_limit": 2200,
"remaining": 0, "grace_remaining": 150, "in_grace_buffer": true,
"notice": "You're in the 10% grace buffer: 2,050 of 2,000 renders used on the Starter plan, 150 left before HTTP 429. Upgrade at https://pdfoven.com/pricing to keep rendering." }
Errors
Errors are JSON: { "error": { "code": "quota_exceeded", "message": "…" } }
| 400 | invalid_request — the body failed validation. |
|---|---|
| 401 | unauthorized — missing or invalid API key. |
| 404 | template_not_found |
| 400 | invalid_pages, unknown_field or invalid_field_value — the message says which page or field. |
| 413 | too_large — a file is over the size limit, or a PDF is too complex to process. |
| 422 | template_error or render_failed (blocked URL, timeout, HTTP error). |
| 422 | invalid_pdf, encrypted_pdf (send password), wrong_password, too_many_pages, no_form, invalid_image, unsupported_text or fetch_failed. |
| 429 | quota_exceeded — monthly limit plus the 10% grace buffer used up. Failed renders don't count. |
| 503 | busy — too many PDF jobs queued. Retry after a few seconds. |
MCP server for AI agents
PDFOven speaks the Model Context Protocol over Streamable HTTP at https://pdfoven.com/mcp. Agents get render_pdf and render_image (including screenshots and social cards); merge_pdfs, split_pdf, compress_pdf, watermark_pdf, list_pdf_form_fields and fill_pdf_form for existing PDFs; and list_templates, get_template, create_template, update_template and delete_template to manage saved templates. Files come back as embedded resources.
Claude Code:
claude mcp add --transport http pdfoven https://pdfoven.com/mcp \
--header "Authorization: Bearer $PDFOVEN_KEY"
Cursor / other clients (mcp.json):
{
"mcpServers": {
"pdfoven": {
"url": "https://pdfoven.com/mcp",
"headers": { "Authorization": "Bearer po_live_..." }
}
}
}
Limits
- Every render counts once, whatever the page count or file size.
- Request bodies up to 6 MB (HTML up to 5 MB); renders time out after 30 seconds by default, up to 60 seconds with
timeout_ms; each resource a page fetches is capped at 50 MB. - PDF tools take files up to 50 MB each and 60 MB per request, up to 5,000 pages each.
- Renders keep working through a 10% grace buffer past your plan's monthly limit (110 on Free), then return 429 until the 1st (UTC).
- URL rendering is limited to public addresses.
- Rendered and uploaded files are processed in memory and never stored.
Support
Questions or a render that looks wrong? Email support@pdfoven.com with the request you sent and the error code you got back.