API reference
Docmill API
JSON in, documents out. One REST API renders PDF, DOCX, and XLSX files from templates — including four built-in starters and templates drafted for you by AI.
Base URL: https://api.docmill.io · All request and error
bodies are JSON. Successful document renders return the binary file unless you ask
for base64.
Quickstart
From nothing to an invoice PDF in under a minute. Sign up for a free key
(50 documents/month, no card), then render the built-in
starter:invoice template.
# 1. Create a free account — the API key is shown once, save it curl -s https://api.docmill.io/signup \ -H "Content-Type: application/json" \ -d '{"name": "Ada Lovelace", "email": "ada@example.com"}' # → 201 {"account_id":"acc_…","api_key":"dk_live_…","plan":"free"} export DOCMILL_API_KEY=dk_live_your_key_here # 2. Render an invoice PDF from a starter template curl https://api.docmill.io/v1/documents \ -H "Authorization: Bearer $DOCMILL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_id": "starter:invoice", "data": { "invoiceNumber": "INV-2026-0001", "issueDate": "2026-08-29", "dueDate": "2026-09-28", "currency": "USD", "company": {"name": "Acme Studio LLC", "address": "100 Market St", "email": "billing@acme.studio"}, "client": {"name": "Northwind Traders", "address": "1 Harbor Way"}, "items": [{"description": "Design sprint", "quantity": 1, "unitPrice": 4800}], "subtotal": 4800, "taxRate": 8, "taxAmount": 384, "total": 5184 } }' --output invoice.pdf # → invoice.pdf (%PDF-1.7 …)
That is the whole loop. Everything below is detail: your own templates, DOCX/XLSX output, base64 and async modes, and billing.
Authentication
Every /v1/* endpoint requires a bearer token — the API key you
received at signup, starting with dk_live_:
Authorization: Bearer dk_live_…
Requests without a valid key return
401 {"error": "invalid or missing API key"}. Keys are shown once at
signup; store them in a secret manager, not in workflow definitions. The examples on
this page assume export DOCMILL_API_KEY=dk_live_….
Sign up
POST /signup
Creates an account and issues an API key. No authentication required; rate-limited per IP. New accounts start on the free plan: 50 documents/month with a small watermark line rendered into PDFs.
| Field | Type | Description |
|---|---|---|
name required | string | Your name or company name. |
email required | string | Contact email for the account. |
curl https://api.docmill.io/signup \
-H "Content-Type: application/json" \
-d '{"name": "Ada Lovelace", "email": "ada@example.com"}'
# 201 Created { "account_id": "acc_8c1f2b6d94e04a31b7aa", "api_key": "dk_live_5f2e…", ← shown once — save it now "plan": "free" }
Usage
GET /v1/usage
Your current month's document consumption against the plan quota. Every successful render — sync, async job, or AI template generation — counts as one document.
curl https://api.docmill.io/v1/usage \
-H "Authorization: Bearer $DOCMILL_API_KEY"
# 200 OK
{
"plan": "free",
"month": "2026-08",
"docs_used": 12,
"docs_included": 50,
"docs_remaining": 38
}
Generate a document
POST /v1/documents
Renders a template with your data. By default the response is the
binary file with Content-Type set to the document's
MIME type and Content-Disposition: attachment; filename="document.pdf"
(or .docx/.xlsx).
| Field | Type | Description |
|---|---|---|
template_id one of | string | A saved template id (tpl_…) or a starter id (starter:invoice, starter:quote, starter:report, starter:certificate). |
html one of | string | Inline Handlebars HTML instead of a saved template. Inline HTML renders to pdf output only. One of template_id or html is required. |
data optional | object | JSON bound into the template. Defaults to {}. |
output optional | string | pdf (default), docx, or xlsx. HTML templates render to PDF only; a DOCX or XLSX template renders to its own format — the output must match the template kind. |
pdf_options optional | object | Page setup for PDF output — see PDF options. |
| Query param | Effect |
|---|---|
?encoding=base64 | Return JSON with the file base64-encoded instead of raw bytes — see Base64 responses. |
?async=1 | Queue the render and return 202 with a job id — see Async jobs. |
# Render with a saved template curl https://api.docmill.io/v1/documents \ -H "Authorization: Bearer $DOCMILL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_id": "tpl_9f2c41d6a8be4a17c0de", "data": {"customer": "Northwind Traders", "amount": 5184}, "output": "pdf" }' --output document.pdf
# Inline HTML — no saved template needed (PDF only) curl https://api.docmill.io/v1/documents \ -H "Authorization: Bearer $DOCMILL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "html": "<h1>Receipt {{number}}</h1><p>{{money amount currency}} received. Thank you!</p>", "data": {"number": "R-1001", "amount": 49, "currency": "USD"} }' --output receipt.pdf
Render failures return 422 with a machine-readable
code; quota exhaustion returns 429 with an
upgrade URL. See Errors.
Base64 responses
Automation platforms and agents often prefer JSON over raw bytes. Add
?encoding=base64 to get the file wrapped in JSON:
curl "https://api.docmill.io/v1/documents?encoding=base64" \ -H "Authorization: Bearer $DOCMILL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"template_id": "starter:certificate", "data": {"recipientName": "Jordan Ellis", "courseName": "Advanced Workflow Automation", "completedAt": "2026-08-20", "issuerName": "Automation Academy"}}' # 200 OK # {"content_type": "application/pdf", "extension": "pdf", "data_base64": "JVBERi0xLjc…"}
PDF options
The pdf_options object controls page setup for PDF output
(ignored for DOCX/XLSX):
| Field | Type | Description |
|---|---|---|
pageFormat | string | "A4" (default), "Letter", or "Legal". |
landscape | boolean | Landscape orientation. Defaults to false. |
marginMm | number | Uniform page margin in millimeters. Defaults to 14. |
"pdf_options": {"pageFormat": "Letter", "landscape": true, "marginMm": 10}
Async jobs
For bulk runs, add ?async=1. The request is validated, queued, and
acknowledged immediately with 202; poll the job until it is done and
decode data_base64.
curl "https://api.docmill.io/v1/documents?async=1" \ -H "Authorization: Bearer $DOCMILL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"template_id": "starter:report", "data": {"title": "Growth report", "period": "August 2026"}}' # 202 Accepted # {"job_id": "job_c41d6a8be4a17c0de9f2", "status": "queued"}
GET /v1/jobs/:id
curl https://api.docmill.io/v1/jobs/job_c41d6a8be4a17c0de9f2 \ -H "Authorization: Bearer $DOCMILL_API_KEY" # 200 OK { "job_id": "job_c41d6a8be4a17c0de9f2", "status": "done", ← queued | processing | done | error "content_type": "application/pdf", "data_base64": "JVBERi0xLjc…", "error": null ← failure message when status is "error" }
Templates
GET /v1/templates
Lists your saved templates plus the four built-in read-only starters every account can render immediately:
| Starter id | Name | Description |
|---|---|---|
starter:invoice | Invoice | Clean line-item invoice with totals, tax, and payment terms. |
starter:quote | Quote | Sales quote with validity window and per-item options. |
starter:report | Monthly report | Metric summary report with a highlights table. |
starter:certificate | Certificate | Completion certificate, landscape, presentation-ready. |
curl https://api.docmill.io/v1/templates \ -H "Authorization: Bearer $DOCMILL_API_KEY" # 200 OK { "templates": [ {"id": "tpl_9f2c41d6a8be4a17c0de", "name": "Consulting invoice", "kind": "html", "created_at": "2026-08-29T09:12:33.000Z", "updated_at": "2026-08-29T09:12:33.000Z"} ], "starters": [ {"id": "starter:invoice", "name": "Invoice", "kind": "html", "description": "Clean line-item invoice with totals, tax, and payment terms.", "readonly": true} … quote, report, certificate ] }
POST /v1/templates
Saves a reusable template. HTML templates are Handlebars sources rendered to
PDF; DOCX templates are Word files with {{marker}} commands; XLSX
templates are spreadsheets with ${marker} placeholders — upload the
binary kinds as base64.
| Field | Type | Description |
|---|---|---|
name required | string | Display name. |
kind optional | string | html (default), docx, or xlsx. |
html | string | Handlebars HTML source. Required when kind is html. |
file_base64 | string | Base64-encoded template file. Required when kind is docx or xlsx. |
sample_data optional | object | Example payload stored with the template, handy for connectors and teammates. |
curl https://api.docmill.io/v1/templates \ -H "Authorization: Bearer $DOCMILL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Receipt", "kind": "html", "html": "<h1>Receipt {{number}}</h1><p>{{money amount currency}} received from {{customer}}.</p>", "sample_data": {"number": "R-1001", "amount": 49, "currency": "USD", "customer": "Northwind"} }' # 201 Created # {"id": "tpl_9f2c41d6a8be4a17c0de", "name": "Receipt", "kind": "html"}
POST /v1/templates/generate
The template editor you don't have to learn: describe the document in plain
language (or paste an old HTML document to imitate) and the AI drafts a Handlebars
HTML template plus sample data showing exactly which fields to send. The result is
saved to your account unless you pass save: false. Each generation
counts as one document of quota.
| Field | Type | Description |
|---|---|---|
prompt one of | string | Plain-language description of the document you need. |
sample_html one of | string | Existing HTML to restyle into a template. One of prompt or sample_html is required. |
name optional | string | Template name; defaults to an AI-suggested one. |
save optional | boolean | Default true (201 with an id). Pass false to preview only (200, id is null). |
curl https://api.docmill.io/v1/templates/generate \ -H "Authorization: Bearer $DOCMILL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "A consulting invoice with line items, 8% tax, EU VAT number, and 30-day payment terms"}' # 201 Created { "id": "tpl_41d6a8be4a17c0de9f2c", "name": "Consulting invoice", "kind": "html", "html": "<html>…{{#each items}}…{{/each}}…</html>", "sample_data": {"items": [{"description": "…", "quantity": 1, "unitPrice": 1200}], "vatNumber": "EU123…"} }
Returns 503 if the server has no AI key configured,
and 429 when your monthly quota is already spent.
GET /v1/templates/:id
Fetches one template, including its HTML source and stored sample data. Every template is plain HTML underneath — inspect it, tweak it, own it.
curl https://api.docmill.io/v1/templates/tpl_9f2c41d6a8be4a17c0de \ -H "Authorization: Bearer $DOCMILL_API_KEY" # 200 OK { "id": "tpl_9f2c41d6a8be4a17c0de", "name": "Receipt", "kind": "html", "html_source": "<h1>Receipt {{number}}</h1>…", "sample_data_json": "{\"number\":\"R-1001\",\"amount\":49}", "created_at": "2026-08-29T09:12:33.000Z", "updated_at": "2026-08-29T09:12:33.000Z" }
DELETE /v1/templates/:id
curl -X DELETE https://api.docmill.io/v1/templates/tpl_9f2c41d6a8be4a17c0de \ -H "Authorization: Bearer $DOCMILL_API_KEY" # 200 OK {"deleted": true}
Both return 404 {"error": "template not found"} for unknown ids
(starters cannot be fetched or deleted this way — they are read-only).
Templating & helpers
HTML templates are standard Handlebars: {{field}},
nested paths ({{client.name}}), {{#each}},
{{#if}}, and ../ to reach parent scope inside loops.
Missing fields render as empty strings rather than failing. Five formatting
helpers are registered for every template:
| Helper | Signature | Behavior |
|---|---|---|
money | {{money value currency}} | Formats a number as currency in en-US style, e.g. $4,800.00. currency is an optional 3-letter ISO code (default USD; anything else falls back to USD). Non-numeric values render empty. |
formatDate | {{formatDate value style}} | Parses a date string or Date; renders the long en-US form (August 29, 2026) by default, or pass "short" for 8/29/26. Invalid dates render empty. |
lineTotal | {{lineTotal qty unitPrice}} | Returns qty × unitPrice as a number (0 if either is not numeric). Usually wrapped in money. |
multiply | {{multiply a b}} | Returns a × b as a raw number. |
sum | {{sum items "field"}} | Sums field across an array of objects; call as {{sum numbers}} to sum an array of plain numbers. Non-numeric entries count as 0; a non-array returns 0. |
A complete miniature example — template, data, and what the PDF shows:
<!-- template -->
<h1>Invoice {{number}} · {{formatDate issueDate}}</h1>
<table>
{{#each items}}
<tr><td>{{this.description}}</td>
<td>{{this.quantity}} × {{money this.unitPrice ../currency}}</td>
<td>{{money (lineTotal this.quantity this.unitPrice) ../currency}}</td></tr>
{{/each}}
<tr><td colspan="2"><b>Total</b></td>
<td><b>{{money (sum items "amount") currency}}</b></td></tr>
</table>
// data
{
"number": "INV-7",
"issueDate": "2026-08-29",
"currency": "EUR",
"items": [
{"description": "Design sprint", "quantity": 1, "unitPrice": 4800, "amount": 4800},
{"description": "Implementation", "quantity": 32, "unitPrice": 120, "amount": 3840}
]
}
# rendered
Invoice INV-7 · August 29, 2026
Design sprint 1 × €4,800.00 €4,800.00
Implementation 32 × €120.00 €3,840.00
Total €8,640.00
Tip: templates are complete HTML pages — include your own
<style> block for fonts, tables, and layout. The starter
templates (fetch one with a render, or study the samples on the
landing page) are good references.
Billing
Paid plans are handled through Stripe. Upgrading is two calls: create a checkout session, open the returned URL in a browser, pay. Manage or cancel any time through the customer portal.
POST /v1/billing/checkout
| Field | Type | Description |
|---|---|---|
plan required | string | "starter", "growth", or "scale". |
curl https://api.docmill.io/v1/billing/checkout \ -H "Authorization: Bearer $DOCMILL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"plan": "growth"}' # 200 OK {"url": "https://checkout.stripe.com/c/pay/cs_live_…"} # open the URL in a browser to complete payment
POST /v1/billing/portal
Returns a Stripe customer-portal link where you can change plan, cancel, and download invoices.
curl -X POST https://api.docmill.io/v1/billing/portal \ -H "Authorization: Bearer $DOCMILL_API_KEY" # 200 OK {"url": "https://billing.stripe.com/p/session/…"}
GET /v1/billing
curl https://api.docmill.io/v1/billing \ -H "Authorization: Bearer $DOCMILL_API_KEY" # 200 OK { "plan": "growth", "billing_configured": true, "has_subscription": true }
Errors & rate limits
Errors are JSON with an error message; render failures add a
machine-readable code:
# 422 Unprocessable Entity
{
"error": "Template failed to compile: Parse error on line 3 …",
"code": "template_compile_error"
}
| Status | Meaning |
|---|---|
400 | Invalid body — missing required field, unknown output format, inline HTML with non-PDF output, or a template kind that cannot render to the requested format. |
401 | Invalid or missing API key. |
404 | Template or job not found (ids are scoped to your account). |
422 | Render failed. code is one of missing_template, template_compile_error (bad Handlebars syntax), template_data_error (template crashed on your data), browser_error (PDF engine failure). |
429 | Monthly quota reached — the body includes an upgrade URL — or rate limited (120 requests/min per key; signup is rate-limited per IP). |
503 | AI template generation is not configured on this server. |
# 429 Too Many Requests (quota)
{
"error": "monthly quota reached (50 documents on the free plan)",
"upgrade": "https://docmill.io/pricing"
}
Plans & quotas
One document costs one document: per-document metering, any format, any page count within reason. No credit blocks, no per-page multipliers.
| Plan | Price | Documents / month | Notes |
|---|---|---|---|
| Free | $0 | 50 | Small watermark line on PDFs. All formats and starters included. |
| Starter | $19/mo | 1,000 | No watermark. AI template generation. |
| Growth | $49/mo | 5,000 | Async bulk jobs, priority support. |
| Scale | $99/mo | 15,000 | Volume tiers above on request. |
Check consumption any time with GET /v1/usage;
upgrade with POST /v1/billing/checkout or from
the pricing page.
Connectors
The API works from anything that can send HTTP, but the connectors are the fast path — all free; your plan meters documents, nothing else.
n8n
Community node n8n-nodes-docmill
(n8n 1.0+). Install via Settings → Community Nodes, add your key
under Credentials → Docmill API.
Operations: Generate Document (file lands in a binary property, ready for email or storage nodes), Generate Template (AI), and List Templates.
Zapier
The Docmill app authenticates with your API key and adds a Generate Document action: pick a template (yours or a starter), map JSON data from earlier steps, choose PDF/DOCX/XLSX.
The generated file is passed to later steps as a real file, plus a template-list trigger powers the dropdown.
Make
The Docmill app's Generate Document module returns the file as binary output, so it pipes directly into Email, Google Drive, Dropbox, and similar modules. Template dropdown included.
MCP (AI agents)
@docmill/mcp-server
is a stdio MCP server (MIT) for Claude and other agents. Tools:
list_templates, generate_document (renders and saves
the file to disk), create_template (AI drafting), and
get_usage.
MCP client configuration:
{
"mcpServers": {
"docmill": {
"command": "npx",
"args": ["-y", "@docmill/mcp-server"],
"env": {"DOCMILL_API_KEY": "dk_live_…"}
}
}
}