API Reference
Convert Markdown or HTML to a production-ready PDF with a single HTTP request.
Base URL
https://www.docrenders.com
All endpoints accept and return JSON unless otherwise noted. PDF responses are application/pdf.
Authentication
Every render endpoint requires an API key passed as a Bearer token in the Authorization header.
Authorization: Bearer dcr_live_YOUR_API_KEY
Keys are prefixed dcr_live_. Generate keys from your dashboard.
Errors
All errors return a consistent JSON shape:
{
"error": {
"code": "quota_exceeded",
"message": "monthly render limit of 100 reached; upgrade your plan to continue"
}
}
| Code | HTTP | Meaning |
|---|---|---|
unauthorized | 401 | Missing or invalid API key |
quota_exceeded | 429 | Monthly render limit reached |
rate_limited | 429 | Too many requests per minute |
invalid_request | 400 | Malformed JSON, missing fields, or unknown parameters |
missing_fields | 400 | Required template data fields not provided |
render_timeout | 504 | Render exceeded the 26s time limit |
render_failed | 500 | Internal rendering error |
internal_error | 500 | Unexpected server error |
Rate Limits
| Plan | Requests / minute | Renders / month |
|---|---|---|
| Free | 10 | 100 |
| Starter | 60 | 5,000 |
| Pro | 300 | 25,000 |
Exceeding the per-minute limit returns 429 rate_limited. Exceeding the monthly quota returns 429 quota_exceeded.
SDKs
Official client libraries are available for Go, JavaScript/TypeScript, and Python. All SDKs are open source at github.com/JWhist/docrenders-sdks.
Install
go get github.com/JWhist/docrenders-sdks/go
Render from markdown
import docrenders "github.com/JWhist/docrenders-sdks/go"
client := docrenders.NewClient("dcr_live_YOUR_API_KEY")
pdf, err := client.Render(ctx, docrenders.RenderRequest{
Markdown: "# Hello\n\nGenerated by DocRenders.",
Options: docrenders.RenderOptions{Format: "A4"},
})
Render from template + data
pdf, err := client.Render(ctx, docrenders.RenderRequest{
Template: "invoice",
Data: map[string]any{
"name": "Acme Corp",
"date": "2026-06-03",
"total": 1500.00,
"items": []map[string]any{
{"description": "Design", "qty": 1, "unit_price": 1500, "amount": 1500},
},
},
})
Render to signed URL
result, err := client.RenderSignedURL(ctx, docrenders.RenderRequest{
Markdown: "# Report",
})
fmt.Println(result.URL) // expires in 15 minutes
Check usage
usage, err := client.Usage(ctx)
fmt.Printf("%d / %d renders used\n", usage.RendersUsed, usage.RendersLimit)
Install
npm install docrenders-sdk
Render from markdown
import DocRendersClient from "docrenders-sdk";
const client = new DocRendersClient("dcr_live_YOUR_API_KEY");
const pdf = await client.render({
markdown: "# Hello\n\nGenerated by DocRenders.",
options: { format: "A4" },
}); // Uint8Array
Render from template + data
const pdf = await client.render({
template: "invoice",
data: {
name: "Acme Corp",
date: "2026-06-03",
total: 1500,
items: [{ description: "Design", qty: 1, unit_price: 1500, amount: 1500 }],
},
});
Render to signed URL
const { url, expires_at } = await client.renderSignedURL({
markdown: "# Report",
});
console.log(url); // expires in 15 minutes
Error handling
import { DocRendersError } from "docrenders-sdk";
try {
const pdf = await client.render({ markdown: "# Hello" });
} catch (err) {
if (err instanceof DocRendersError) {
console.error(err.code, err.message);
}
}
Check usage
const usage = await client.usage();
console.log(`${usage.renders_used} / ${usage.renders_limit} renders used`);
Install
pip install docrenders-sdk
Render from markdown
from docrenders import DocRendersClient, RenderRequest, RenderOptions
client = DocRendersClient("dcr_live_YOUR_API_KEY")
pdf = client.render(RenderRequest(
markdown="# Hello\n\nGenerated by DocRenders.",
options=RenderOptions(format="A4"),
))
Render from template + data
pdf = client.render(RenderRequest(
template="invoice",
data={
"name": "Acme Corp",
"date": "2026-06-03",
"total": 1500.00,
"items": [{"description": "Design", "qty": 1, "unit_price": 1500, "amount": 1500}],
},
))
Render to signed URL
result = client.render_signed_url(RenderRequest(markdown="# Report")) print(result.url) # expires in 15 minutes
Error handling
from docrenders import DocRendersError
try:
pdf = client.render(RenderRequest(markdown="# Hello"))
except DocRendersError as e:
print(e.code, str(e))
Check usage
usage = client.usage()
print(f"{usage.renders_used} / {usage.renders_limit} renders used")
MCP Server
The DocRenders MCP server lets Claude and any MCP-compatible AI agent generate PDFs directly — no code required. Ask Claude to "generate an invoice for Acme Corp" and it will call the API, fill the template, and return a download link.
The server is published as docrenders-mcp on npm. Node.js 18+ is required.
Install for Claude Desktop
Add the following to your claude_desktop_config.json, then restart Claude Desktop.
{
"mcpServers": {
"docrenders": {
"command": "npx",
"args": ["-y", "docrenders-mcp"],
"env": {
"DOCRENDERS_API_KEY": "dcr_live_YOUR_API_KEY"
}
}
}
}
| OS | Config file location |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
Install for Claude Code
Run the following command to add the server to your Claude Code configuration:
claude mcp add docrenders -- npx -y docrenders-mcp
Then set your API key:
claude mcp add docrenders --env DOCRENDERS_API_KEY=dcr_live_YOUR_API_KEY -- npx -y docrenders-mcp
Example prompts
- "Generate an invoice PDF for Acme Corp, $2,500 for design work, due June 17."
- "Create a PDF resume for Jordan Whistler, senior Go engineer."
- "Convert this markdown to a PDF using the ai-summary template."
- "How many renders have I used this month?"
MCP Tools Reference
| Tool | Description | Key parameters |
|---|---|---|
render |
Convert Markdown or HTML to a PDF. Returns a signed download URL valid for 15 minutes. | markdown or html (required); template, format, landscape (optional) |
render_template |
Generate a PDF from a built-in template with structured data. | template, data (required); format, landscape (optional) |
list_templates |
List all available templates with their required and optional fields. | — |
get_usage |
Check current period render count, plan limit, and rate limit. | — |
All render_template templates and their fields are documented in the Templates section. The MCP server validates required fields before making a request and surfaces any missing_fields errors as readable messages.
POST /render
Synchronously converts Markdown or HTML to a PDF and returns the raw binary.
Request body
{
"markdown": "# Hello\n\nGenerated by DocRenders.",
"template": "invoice",
"data": {
"name": "Acme Corp",
"date": "2026-06-03",
"total": 1500.00,
"items": [{ "description": "Design", "qty": 1, "unit_price": 1500, "amount": 1500 }]
},
"options": {
"format": "A4",
"margin_top": "1in",
"margin_right": "1in",
"margin_bottom": "1in",
"margin_left": "1in",
"landscape": false
},
"output": "binary"
}
| Field | Type | Default | Notes | |
|---|---|---|---|---|
markdown | required* | string | — | Markdown content. GFM supported. |
html | required* | string | — | Raw HTML. Alternative to markdown. |
template | optional | string | — | Built-in template name. See Templates. |
data | optional | object | — | Variables injected into the template. When provided with template, the template supplies the content — no markdown needed. See Templates. |
options.format | optional | string | "A4" | "A4", "Letter", or "Legal" |
options.margin_top | optional | string | "1in" | Any CSS length: "1in", "20mm", "72px" |
options.margin_right | optional | string | "1in" | |
options.margin_bottom | optional | string | "1in" | |
options.margin_left | optional | string | "1in" | |
options.landscape | optional | bool | false | Rotate page to landscape orientation |
output | optional | string | "binary" | "binary" returns raw PDF bytes; "url" returns a signed download URL |
*One of markdown, html, or template + data is required.
Every render is stored server-side regardless of the output value. The output parameter only controls what is returned in the response — the PDF is always retained and accessible via its signed URL.
Response — output=binary (default)
HTTP 200 Content-Type: application/pdf Content-Disposition: attachment; filename="render.pdf" <binary PDF bytes>
Response — output=url
{
"url": "https://storage.docrenders.dev/pdfs/...",
"expires_at": "2026-05-30T15:00:00Z",
"render_time_ms": 1240
}
The signed URL expires after 15 minutes and is scoped to your account — it cannot be used to access another user's files. Use this mode when you want to redirect a user directly to the PDF rather than proxy the bytes through your own server.
Example — binary
curl -X POST https://www.docrenders.com/render \
-H "Authorization: Bearer dcr_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"markdown":"# Hello\n\nGenerated by DocRenders."}' \
--output output.pdf
Example — signed URL
curl -X POST https://www.docrenders.com/render \
-H "Authorization: Bearer dcr_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"markdown":"# Hello\n\nGenerated by DocRenders.","output":"url"}'
POST /render/file
Same as /render but accepts a file upload via multipart/form-data. Supports .md, .markdown, and .html files.
Form fields
| Field | Notes | |
|---|---|---|
file | required | .md, .markdown, or .html — max 10 MB |
format | optional | "A4" (default), "Letter", "Legal" |
margin_top | optional | CSS length, default "1in" |
margin_right | optional | CSS length, default "1in" |
margin_bottom | optional | CSS length, default "1in" |
margin_left | optional | CSS length, default "1in" |
landscape | optional | "true" to enable landscape |
Response
HTTP 200 Content-Type: application/pdf Content-Disposition: attachment; filename="render.pdf" <binary PDF bytes>
Example
curl -X POST https://www.docrenders.com/render/file \ -H "Authorization: Bearer dcr_live_YOUR_API_KEY" \ -F "file=@invoice.md" \ -F "format=A4" \ --output output.pdf
Built-in Templates
Templates can be used in two modes:
- Data mode — pass
template+data. The template supplies the document structure; your data fills the variables. Nomarkdownneeded. - Styling mode — pass
template+markdown. Your markdown content is rendered into the template's styled layout.
Data mode is recommended when you want consistent, predictable output. Required fields are validated server-side — missing any returns a missing_fields error listing exactly which fields are absent.
| Template | Description |
|---|---|
invoice | Professional invoice with line items, totals, sender/recipient blocks, and logo |
receipt | Payment receipt with merchant, items, totals, and payment method |
resume | Clean typographic layout for CVs and resumes |
ai-summary | Dark report header, executive summary callout, key findings, and sections |
report | Business report with executive summary and structured sections |
letter | Formal business letter with sender, recipient, subject, and signature |
proposal | Project or sales proposal with structured sections and logo |
post | WordPress-style blog post with title, author, date, featured image, and Markdown body |
woo-invoice | WooCommerce order invoice with shop details, billing address, line items, and payment info |
Image fields (logo) accept either a public URL or a raw base64-encoded PNG/JPEG string. Base64 values are automatically prefixed with the appropriate data URI.
invoice
Professional invoice with a dark header bar, two-column sender/recipient block, styled line-item table, right-aligned totals, and an optional footer note.
| Field | Type | Description | |
|---|---|---|---|
name | required | string | Client or recipient name |
date | required | string | Invoice date |
total | required | number | Total amount due |
items | required | array | Line items: description, qty, unit_price, amount |
from | optional | string | Sender company name |
from_street | optional | string | Sender street address |
from_city | optional | string | Sender city, state, and zip |
from_email | optional | string | Sender email address |
due_date | optional | string | Payment due date |
invoice_number | optional | string | Invoice reference number |
title | optional | string | Document title (default: Invoice) |
subtotal | optional | number | Subtotal before tax |
tax | optional | number | Tax amount |
notes | optional | string | Footer note or payment instructions |
logo | optional | image | Sender logo — URL or base64 PNG/JPEG |
curl -X POST https://www.docrenders.com/render \
-H "Authorization: Bearer dcr_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "invoice",
"data": {
"from": "Acme Studio",
"from_street": "123 Main St",
"from_city": "San Francisco, CA 94105",
"from_email": "billing@acme.com",
"name": "TechCorp Inc.",
"date": "2026-06-03",
"due_date": "2026-06-17",
"invoice_number": "INV-0089",
"items": [
{ "description": "Design", "qty": 1, "unit_price": 4000, "amount": 4000 },
{ "description": "Development", "qty": 20, "unit_price": 150, "amount": 3000 }
],
"subtotal": 7000,
"tax": 577.50,
"total": 7577.50,
"notes": "Payment due within 14 days. Reference INV-0089 on transfer."
}
}' --output invoice.pdf
receipt
Clean payment receipt with merchant name, transaction metadata, line items, totals, and optional payment method.
| Field | Type | Description | |
|---|---|---|---|
merchant | required | string | Merchant or business name |
date | required | string | Transaction date |
total | required | number | Total charged |
items | required | array | Line items: description, amount |
transaction_id | optional | string | Transaction or order ID |
subtotal | optional | number | Subtotal before tax |
tax | optional | number | Tax amount |
payment_method | optional | string | e.g. Cash or VISA XXXXXX4242 |
notes | optional | string | Footer note or return policy |
logo | optional | image | Merchant logo — URL or base64 PNG/JPEG |
resume
Clean typographic CV layout with sections for experience, education, and skills.
| Field | Type | Description | |
|---|---|---|---|
name | required | string | Full name |
email | required | string | Email address |
phone | optional | string | Phone number |
location | optional | string | City, State or remote |
linkedin | optional | string | LinkedIn URL or handle |
github | optional | string | GitHub URL or handle |
summary | optional | string | Professional summary paragraph |
experience | optional | array | Work history: company, role, dates, bullets (array of strings) |
education | optional | array | Education: school, degree, year |
skills | optional | string | Skills summary — free text or comma-separated |
ai-summary
Dark header report layout with an executive summary callout block, key findings list, and freeform sections. Designed for AI-generated analysis outputs.
| Field | Type | Description | |
|---|---|---|---|
title | required | string | Report title |
date | required | string | Report date |
summary | required | string | Executive summary text |
model | optional | string | AI model name shown in header metadata |
author | optional | string | Author or team name |
key_points | optional | array | Key findings — array of strings |
sections | optional | array | Additional sections: heading, content |
report
General business report with optional logo, executive summary, and structured sections.
| Field | Type | Description | |
|---|---|---|---|
title | required | string | Report title |
author | required | string | Author name or team |
date | required | string | Report date |
sections | required | array | Report sections: heading, content |
executive_summary | optional | string | Executive summary paragraph shown before sections |
logo | optional | image | Organization logo — URL or base64 PNG/JPEG |
letter
Formal business letter with sender address, recipient, subject line, body, and closing signature.
| Field | Type | Description | |
|---|---|---|---|
sender_name | required | string | Sender full name |
recipient_name | required | string | Recipient full name or organization |
date | required | string | Letter date |
body | required | string | Letter body — Markdown supported |
signature_name | required | string | Signature name |
sender_address | optional | string | Sender address block |
recipient_address | optional | string | Recipient address block |
subject | optional | string | Re: subject line |
salutation | optional | string | Opening salutation word (default: Dear) |
closing | optional | string | Closing phrase (default: Sincerely) |
proposal
Project or sales proposal with client and preparer details, structured sections, and optional logo.
| Field | Type | Description | |
|---|---|---|---|
title | required | string | Proposal title |
client | required | string | Client name or organization |
date | required | string | Proposal date |
prepared_by | required | string | Your name or company |
sections | required | array | Proposal sections: heading, content |
logo | optional | image | Your logo — URL or base64 PNG/JPEG |
post
WordPress-style blog post layout with a featured image, byline, category and tag metadata, and a full Markdown body. Used by the DocRenders WordPress plugin to render posts and pages as PDFs.
| Field | Type | Description | |
|---|---|---|---|
title | required | string | Post title |
author | required | string | Author display name |
date | required | string | Publication date |
content | required | string | Post body — Markdown (GFM) supported |
category | optional | string | Primary category label shown in the header |
tags | optional | array | Tag strings displayed below the byline |
featured_image | optional | image | Featured image — public URL or base64 PNG/JPEG |
curl -X POST https://www.docrenders.com/render \
-H "Authorization: Bearer dcr_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "post",
"data": {
"title": "Getting Started with Headless WordPress",
"author": "Jordan Whistler",
"date": "June 6, 2026",
"category": "Development",
"tags": ["WordPress", "Headless", "API"],
"content": "## Introduction\n\nHeadless WordPress separates the CMS from the frontend..."
}
}' --output post.pdf
woo-invoice
WooCommerce order invoice with shop branding, billing address, a line-item table, tax and totals, and payment details. Used by the DocRenders WordPress plugin to generate downloadable invoices for WooCommerce orders.
Note: Both order_number and invoice_number are required — WooCommerce order IDs and invoice reference numbers are treated as distinct fields.
| Field | Type | Description | |
|---|---|---|---|
order_number | required | string | WooCommerce order number (e.g. 10482) |
invoice_number | required | string | Invoice reference (e.g. WC-10482) |
invoice_date | required | string | Invoice date |
shop_name | required | string | WooCommerce store name |
billing_name | required | string | Customer billing name |
due_date | optional | string | Payment due date |
shop_email | optional | string | Store contact email |
shop_address | optional | string | Store address |
billing_email | optional | string | Customer email |
billing_address | optional | string | Customer billing address |
items | optional | array | Line items: name, quantity, price |
subtotal | optional | number | Subtotal before tax |
tax | optional | number | Tax amount |
total | optional | number | Order total |
payment_method | optional | string | Payment method label (e.g. Credit Card (Visa ending 4242)) |
order_status | optional | string | Order status label (e.g. Paid, Processing) |
notes | optional | string | Footer note or customer message |
curl -X POST https://www.docrenders.com/render \
-H "Authorization: Bearer dcr_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "woo-invoice",
"data": {
"order_number": "10482",
"invoice_number": "WC-10482",
"invoice_date": "June 6, 2026",
"shop_name": "Whistler Digital Goods",
"shop_email": "hello@whistlerdigital.com",
"billing_name": "Alex Rivera",
"billing_email": "alex.rivera@example.com",
"items": [
{ "name": "DocRenders Pro Plugin — Annual License", "quantity": 1, "price": 99 },
{ "name": "Priority Support Add-on", "quantity": 1, "price": 49 }
],
"subtotal": 148,
"tax": 13.32,
"total": 161.32,
"payment_method": "Credit Card (Visa ending 4242)",
"order_status": "Paid"
}
}' --output woo-invoice.pdf
WordPress Plugin
The DocRenders WordPress plugin adds a "Download as PDF" button to any post or page — no code required. Site owners install the plugin, enter their API key, and readers get a one-click PDF download of the content.
Installation
- Download the latest
docrenders.zipfrom the GitHub releases page. - In your WordPress admin, go to Plugins → Add New → Upload Plugin and upload the zip.
- Activate the plugin.
- Go to Settings → DocRenders and enter your API key (
dcr_live_…).
Shortcode
Place the shortcode anywhere in a post or page to add a download button:
[docrenders]
Optional attributes let you customize the output:
[docrenders label="Download PDF" template="post" format="A4"]
| Attribute | Default | Description |
|---|---|---|
label | Download PDF | Button label text |
template | post | DocRenders template to use — post for posts/pages |
format | A4 | Page size: A4, Letter, or Legal |
How it works
When a visitor clicks the button, the browser posts to a WordPress REST endpoint registered by the plugin:
POST /wp-json/docrenders/v1/render
The endpoint reads the post content server-side, attaches the stored API key, calls the DocRenders API, and streams the PDF back to the browser. The API key is never exposed to the client.
WooCommerce Invoices
When WooCommerce is active, the DocRenders plugin automatically generates an invoice PDF and attaches it to the order completion email when an order's status changes to Completed. No configuration is needed beyond installing the plugin and setting your API key.
Invoices are rendered using the woo-invoice template. Order data (line items, billing address, totals, payment method) is pulled directly from the WooCommerce order object.
Admin: generate invoice for any order
From WooCommerce → Orders, open any order and click Generate PDF Invoice in the Order Actions panel. The PDF is generated on demand and streamed to the browser.
Customising invoice output
The woo-invoice template is populated automatically from WooCommerce order data. To override any field — for example, to add a custom footer note — use the docrenders_woo_invoice_data filter:
add_filter( 'docrenders_woo_invoice_data', function( $data, $order ) {
$data['notes'] = 'Thank you for shopping with us! Questions? Email support@yourstore.com.';
return $data;
}, 10, 2 );
The $data array contains all fields documented in the woo-invoice template reference above.
