API documentation

DocForge turns an HTML template and JSON data into a PDF or PNG. One endpoint, one key, no SDK needed.

New here? Create an account (100 free credits every month), create an API key, then run:
curl https://api.docforge.dev/v1/render \
  -H "Authorization: Bearer $DOCFORGE_KEY" \
  -H "Accept: application/pdf" \
  -d '{"html":"<h1>Hello {{name}}</h1>","data":{"name":"World"}}' \
  -o document.pdf

Authentication

Send your key as Authorization: Bearer df_live_… or X-API-Key: df_live_…. Keys are shown once; revoke and recreate them in the dashboard. Rate limit: 10 requests per second per key, bursts up to 30.

Render a document

POST /v1/render with a JSON body:

FieldTypeDescription
template_idstringA saved template. Use this or html.
html, cssstringInline template, up to 5 MB. A fragment is fine; we add the document wrapper.
dataobjectValues for the placeholders.
output"pdf" | "png"Default pdf.
optionsobjectOverrides the template's page options, see below.
asyncbooleanQueue the job and return 202 immediately.
webhook_urlhttps URLWith async: where we POST the result.

Getting the file. With Accept: application/pdf (or image/png) the response body is the file, and the headers X-Render-Id, X-Pages, X-Credits-Used, X-Credits-Remaining describe it. Without it you get JSON with a link valid for 24 hours:

Response
{
  "id": "rnd_lt6vl7zp2nx3h6ygtooy",
  "status": "succeeded",
  "output": "pdf",
  "pages": 1,
  "credits_used": 1,
  "credits_remaining": 99,
  "url": "https://api.docforge.dev/files/r/rnd_lt6vl7zp2nx3h6ygtooy.pdf?exp=…&sig=…",
  "expires_at": "2026-10-05T10:53:21Z"
}

Other endpoints: GET /v1/renders/:id (status and a fresh link), GET /v1/templates, GET /v1/templates/:id, GET /v1/account (balance).

Page options

OptionApplies toDefault
formatPDFA4. Also A3, A5, Letter, Legal
landscapePDFfalse
margin_mmPDF10
widthPNG1200 px
heightPNG0 = full page
scalePNG1. Use 2 for retina

CSS @page rules in the template win over these. Images and fonts load from public URLs (Google Fonts works); private and internal addresses are blocked. Rendering times out after 30 seconds; documents are limited to 200 pages.

Templates & helpers

Templates use Handlebars. {{x}} is HTML-escaped, {{{x}}} inserts raw HTML. Loop with {{#each items}}…{{/each}} and use ../field to reach outside the loop.

Helpers
{{formatMoney total "EUR"}}            → €1,234.50
{{formatNumber 1234.5 2}}              → 1,234.50
{{formatDate issued_at "Jan 2, 2006"}} → Oct 4, 2026   (Go date layout)
{{multiply quantity unit_price}}       {{plus a b}}
{{sumBy items "amount"}}               {{upper s}}  {{lower s}}
{{orDefault note "—"}}                 {{#ifEq status "paid"}}PAID{{/ifEq}}

Page breaks: <div style="page-break-after: always"></div>. Repeat table headers on every page with thead { display: table-header-group }.

Async & webhooks

Send "async": true and an optional webhook_url. We POST {"type": "render.succeeded" | "render.failed", "data": {…}} and retry with backoff for about 3 hours until your endpoint answers 2xx. Verify the X-DocForge-Signature header with the webhook secret from the API keys page:

import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // replay protection
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}

Errors

Every error looks like {"error": {"code": "…", "message": "…"}}. Failed renders never cost credits.

StatusCodeMeaning
400bad_requestInvalid JSON or fields
401unauthorizedMissing, wrong or revoked key
402insufficient_creditsTop up in Billing
404template_not_foundNo such template on your account
413too_largeHTML over 5 MB
422template_error, too_many_pagesHandlebars syntax error, or over 200 pages
429rate_limitedSlow down; see Retry-After
504render_timeoutTook over 30 s, usually a slow external image

AI agents (MCP)

DocForge is an MCP server at https://api.docforge.dev/mcp (Streamable HTTP) with tools render_document, list_templates and get_balance.

claude mcp add --transport http docforge https://api.docforge.dev/mcp \
  --header "Authorization: Bearer df_live_…"

Then ask your agent: "Make an invoice PDF for Globex: 3 hours of consulting at $120."

No-code: n8n, Zapier, Make, Activepieces

Every integration has the same idea: pick a template, map your data onto its fields, and get the PDF back as a file the next step can attach to an email or upload to Drive.

ToolHow to add it
n8nSettings → Community nodes → install n8n-nodes-docforge. Also works as a tool for n8n AI agents.
ZapierSearch for DocForge when adding an action, then choose Render Document.
MakeAdd the DocForge app to a scenario and use Render a document.
ActivepiecesAdd the DocForge piece and use Render Document.

Anything else (Pipedream, Power Automate, Retool, Bubble): use an HTTP request step with POST https://api.docforge.dev/v1/render, the header Authorization: Bearer df_live_… (or X-API-Key) and the JSON body above. Leave out Accept to get a link, or set Accept: application/pdf to get the file.

ChatGPT & OpenAPI

The API is described in OpenAPI 3.1 at https://api.docforge.dev/openapi.json. Import it into Postman, Dify, Flowise, Langflow or any code generator.

Custom GPT: in the GPT editor open Configure → Actions → Create new action, choose Import from URL and paste the link above. Set authentication to API key → Bearer with your key. Your GPT can now list your templates and hand users a download link to a finished PDF.

Credits

1 credit = 1 PDF page or 1 PNG. Free credits (100 a month) are used first and refill monthly; purchased credits never expire. Previews in the dashboard editor are free and watermarked.