Create a template
Templates are the layout that PDF generation renders against your data. Design them visually with drag-and-drop, write raw HTML/CSS with Handlebars, or create them through the API.
Getting started
From your dashboard, open All templates in the sidebar and click New template. Choose Code + Handlebars or Visual designer.
In the visual designer, place text blocks, images, tables, and shapes with drag-and-drop. In code mode, write HTML and CSS directly.
Use Handlebars syntax anywhere in the template to inject values from your JSON payload at generation time. For example: {{customer.name}}.
Add a JSON Schema to document expected input fields. Agents use this to construct correctly-shaped payloads when generating PDFs via MCP.
Click Publish. Generation always uses the latest published version, so draft edits have no effect until you publish again. Copy the Template ID (a UUID) — you'll pass it as templateId in generate requests.
Page size and orientation
Set page size (A4, Letter, or Legal), orientation (portrait/landscape), margins, headers and footers in the template's PDF settings. They are saved with the template and cannot be changed per generation request.
Assets
Upload logos, images, and custom fonts from Settings → Assets. Use the returned renderPath in your template HTML or CSS. See Template assets for details.
Create a template via the API
With an API key that has the template:write scope you can create, edit and publish templates from code:
POST /v1/templateswithname(1–200 characters), optionaldescription(up to 1,000) and optionalmode(code,visualorpdfox-builder; defaultcode). Returns201with the template.PATCH /v1/templates/{id}updates the draft. Fields:html,css,sampleJson(a JSON object, not a string),schema,bindings,grapesjs,builderSchema,metadata,name,description. Unknown fields such asdraftHtmlare silently ignored.POST /v1/templates/{id}/publishsnapshots the draft into a new version and returns{ "version": { "id", "versionNumber", ... } }. The body is optional; passsourceVersionIdto re-publish an earlier version. Returns422 UNPROCESSABLEif the draft HTML is empty, or if this is the first publish and your plan's template limit is reached.
GET /v1/templates/{id} returns the draft as draftHtml, draftCss, draftSchema and draftSampleJson, with the authoring mode in metadata.mode. GET /v1/templates (scope template:read) returns { "templates", "templateLimit" }: up to 50 templates, most recently updated first.
curl -X POST https://api.pdf-fox.com/v1/templates -H "Authorization: Bearer $PDFOX_API_KEY" -H "Content-Type: application/json" -d '{ "name": "Invoice Template", "mode": "code" }'
# 201 Created → { "id": "a3f1d2e4-1111-4562-b3fc-2c963f66afa6", ... }Payload validation (optional)
By default PDFox accepts any data object and leaves optional fields empty. To reject requests that don't match your template's JSON Schema instead, turn on Reject requests that don't match the schema in the editor's Settings tab, or send { "metadata": { "validatePayload": true } } in PATCH /v1/templates/{id}.
- Checked against the published version's schema, before any credit is used. Draft edits don't count until you publish.
- A mismatch returns
400 VALIDATION_ERRORwith adetailsentry per failing field, e.g.{ "field": "data.items.0.qty", "message": "must be integer" }. - If the schema itself is invalid you get
422 TEMPLATE_SCHEMA_INVALID; fix and republish it, or turn the setting off. - The setting takes effect immediately and applies to REST, MCP and dashboard generation. Retries of an already-accepted job aren't re-checked.
Template ID
The template ID is a UUID, for example a3f1d2e4-1111-4562-b3fc-2c963f66afa6. It appears in the template editor URL and is returned as id by the API. Pass it as templateId in every generate request.
