Skip to main content

Documentation

Guides & documentation

Everything you need to design templates in the builder, issue API keys, and generate PDFs from your existing software.

Overview

Docuplate lets you design PDF templates visually, bind them to JSON, and generate documents from your app or backend via API keys. The typical workflow is: design → save → test with sample JSON → integrate.

  1. Create a template in the builder (or import an existing PDF as a starting point).
  2. Map block fields to JSON paths using {{customer.name}} syntax.
  3. Save the template and note the template ID from the URL (/templates/…/builder).
  4. Create an API key and call the public generate endpoint from your system.

Using the builder

Open Templates and click New template or Open builder on an existing template.

Layout

  • Left panel: block library and layer list (drag to reorder).
  • Canvas: live preview of the PDF page; click a block to select it.
  • Right panel: inspector for the selected block (labels, paths, styles).
  • Data & tools: sample JSON editor, AI audit, and API code snippets.

Adding blocks

Click Insert here between blocks to open the block picker, or use the block library on the left. Common blocks include Header, Info grid, Table, Totals, Notes, Signature, Divider, and Image.

Save & preview

Click Save to persist changes. Use Generate PDF to render with the current sample JSON. The download link appears in the banner at the top.

PDF import

From Templates, choose Import PDF to upload an existing document. Docuplate extracts structure and creates editable blocks where possible; complex regions may be flagged for manual review.

Mobile & tablet

On smaller screens the side panels collapse into a bottom dock: Blocks, Inspect, Data, Save, and PDF. Pinch to zoom the canvas.

Variables & sample data

Blocks bind to your payload using double-curly variables. Paths use dot notation and match the JSON you send at generation time.

{{customer.name}}
{{invoice.number}}
{{items[].description}}
{{totals.total}}

Open the JSON tab in Data & tools to edit sample data. The inspector suggests paths from this JSON when editing text fields. Missing values render as empty rather than breaking the layout.

Table blocks read from an array path (e.g. items). Map each column to a field on the row object (description, qty, etc.).

API keys

API keys authenticate server-to-server PDF generation. They are separate from your login session (JWT).

  1. Go to API Keys in the app.
  2. Enter a descriptive name (e.g. Production billing worker) and click Create.
  3. Copy the key immediately. It starts with df_ and is only shown once.
  4. Store it in your secrets manager or environment variables, never in client-side code or git.

Send the key as Authorization: Bearer df_… on every generate request. Revoke compromised keys from the API Keys page; last-used timestamps help you audit activity.

Generation API

Endpoint: POST /api/public/templates/:templateId/generate

Base URL: http://127.0.0.1:4270 (set VITE_API_URL in production to match your deployed API).

Request

POST /api/public/templates/{templateId}/generate
Authorization: Bearer df_your_api_key
Content-Type: application/json

{
  "data": { /* your JSON payload; same shape as builder sample data */ }
}

If data is omitted, the template's saved sample data is used (useful for smoke tests only).

Response

{
  "fileUrl": "https://your-api.example.com/api/downloads/….pdf?exp=…&sig=…",
  "warnings": ["Optional layout warnings"],
  "errors": []
}

A 200 response with a fileUrl means success. Download the PDF from that URL. Non-empty warnings indicate non-fatal issues (missing fields, etc.). Check errors when generation fails.

Examples

cURL

curl -X POST 'http://127.0.0.1:4270/api/public/templates/YOUR_TEMPLATE_ID/generate' \
  -H 'Authorization: Bearer df_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "data": {
      "invoice": { "number": "INV-1042", "date": "2026-06-05" },
      "customer": { "name": "Acme Ltd", "email": "[email protected]" },
      "items": [
        { "sku": "W-01", "description": "Widget", "qty": 2, "price": 49.5 }
      ],
      "totals": { "subtotal": 99, "tax": 9.9, "total": 108.9 }
    }
  }'

Node.js

const response = await fetch(
  `${process.env.DOCUPLATE_API_URL}/api/public/templates/${templateId}/generate`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.DOCUPLATE_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ data: invoicePayload }),
  },
);

if (!response.ok) throw new Error(await response.text());
const result = await response.json();
// result.fileUrl; download or store the PDF

Python

import os, requests

resp = requests.post(
    f"{os.environ['DOCUPLATE_API_URL']}/api/public/templates/{template_id}/generate",
    headers={"Authorization": f"Bearer {os.environ['DOCUPLATE_API_KEY']}"},
    json={"data": invoice_payload},
    timeout=120,
)
resp.raise_for_status()
result = resp.json()
pdf_url = result["fileUrl"]

Connect your system

Call the generate endpoint from a trusted backend: your ERP, billing system, workflow engine, or a queue worker, whenever a document should be produced.

Recommended pattern

  1. Store DOCUPLATE_API_KEY and DOCUPLATE_API_URL as secrets.
  2. Map each document type to a template ID (invoice → tpl_abc, delivery note → tpl_def).
  3. When an event fires (order paid, shipment ready), build the JSON payload and POST to generate.
  4. Fetch fileUrl, attach to email, upload to S3, or file in your DMS.
  5. Log warnings and surface failures to your ops channel.

Common integrations

  • Webhook handler: Stripe, Shopify, or custom webhooks trigger generation after payment.
  • Scheduled jobs: nightly statement runs via cron + worker process.
  • Internal microservice: your API gateway forwards document requests to Docuplate.
  • No-code bridges: Zapier/Make HTTP modules with the same curl payload.

The builder's API example tab shows a ready-made curl command for the open template with your current sample JSON. Copy it as a starting point.

No-code: Bubble, Webflow & Make

Docuplate works with no-code platforms when PDF generation runs on the server side of that platform (or through an automation tool). Never from the visitor's browser with your API key embedded in the page.

Flow: user action → backend workflow or automation → Docuplate API → PDF URL → email / download / database.

Before you start

  1. Finish your template in the Docuplate builder and copy the template ID from the URL.
  2. Create an API key on the API Keys page and store it as a private secret in your no-code tool.
  3. Match your platform's fields to the same JSON shape as the builder's sample data (see Variables).
  4. Test once with the curl example from Generation API before wiring the no-code workflow.

Bubble.io

Bubble is a strong fit because workflows can call external APIs with secrets kept off the page.

  1. Open Plugins → API Connector and add a new shared call named e.g. Docuplate Generate PDF.
  2. Set Use as to Action, method POST, URL {API_URL}/api/public/templates/{template_id}/generate (replace with your real API URL and template ID, or use dynamic parameters).
  3. Add header Authorization = Bearer YOUR_DF_KEY (mark the key private in the connector. Do not expose on the client).
  4. Set body type to JSON and map Bubble fields into a data object.
  5. In a workflow (e.g. When Order is created or a button Generate invoice), add action Plugins → Docuplate Generate PDF.
  6. Use Result of step 1's fileUrl to open a new tab, save on the Thing, or pass to an email plugin.

Example Bubble JSON body

{
  "data": {
    "customer": {
      "name": "<Order's Customer's name>",
      "email": "<Order's Customer's email>"
    },
    "invoice": {
      "number": "<Order's invoice number>",
      "date": "<Order's Created Date formatted as ISO date>"
    },
    "items": [
      {
        "sku": "SKU-1",
        "description": "Example line item",
        "qty": 1,
        "price": 49.5
      }
    ],
    "totals": {
      "subtotal": 49.5,
      "tax": 4.95,
      "total": 54.45
    }
  }
}

For repeating line items, build the items list from a Bubble :filtered or backend workflow that formats related Things as JSON. Field names must match the paths in your template (e.g. {{customer.name}}data.customer.name).

Tip: Run the API call in a workflow action, not in an element that runs in the browser with the key visible in dev tools.

Webflow

Webflow does not natively store API secrets for arbitrary server POST calls on form submit. Use one of these patterns:

  • Make (Integromat) or Zapier: recommended for marketers and form-driven PDFs (see below).
  • Small middleware: a Cloudflare Worker or similar that holds your Docuplate key; Webflow calls your worker, not Docuplate directly.
  • Webflow Logic / custom backend: if you already run server code on form events, call Docuplate from there with env-stored secrets.

Do not put your df_ key in Webflow custom code on a published page. Anyone can view source and steal it.

Make (Integromat) + Webflow

  1. Webflow: form or e-commerce event sends a webhook to Make (native Webflow modules available).
  2. Make: add HTTP module: POST http://127.0.0.1:4270/api/public/templates/YOUR_TEMPLATE_ID/generate.
  3. Headers: Authorization: Bearer [stored secret], Content-Type: application/json.
  4. Body: map Webflow form fields into data (use Make's JSON module or structure mode).
  5. Parse response JSON → take fileUrl → next module: Gmail/SendGrid (attach link), Google Drive upload, or update Airtable/Notion.

Make HTTP module body (minimal)

{
  "data": {
    "customer": {
      "name": "{{1.name}}",
      "email": "{{1.email}}"
    },
    "invoice": {
      "number": "{{1.order_id}}",
      "date": "{{1.submitted_at}}"
    }
  }
}

Replace {{1.…}} with Make's mapped fields from the Webflow webhook step. Add items and totals arrays/objects to match your template.

Zapier (alternative)

Same idea as Make:

  1. Trigger: Webflow Form Submission (or another app).
  2. Action: Webhooks by Zapier → POST to Docuplate generate URL with Bearer auth.
  3. Action: Email by Zapier / Google Drive: send or store fileUrl from the webhook response.

Field mapping checklist

  • Every {{variable}} in the template needs a matching key in data.
  • Table blocks need an array at the path you configured (e.g. data.items).
  • Dates and numbers should be strings or numbers as your template expects; test with sample data first.
  • Check the API response warnings array for missing paths before going live.

End-to-end examples

Bubble: “Download invoice” button: Button clicked → workflow calls Docuplate → saves fileUrl on Order → opens link in new tab.

Webflow: “Request quote” form: Form submitted → Make webhook → Docuplate generate → Make emails customer the PDF link from fileUrl.

Security & limits

  • Never expose API keys in browsers, mobile apps, or public repositories.
  • Rotate keys periodically and revoke unused keys.
  • Template IDs are not secret but keys must stay private. Possession of a key grants generation for your account's templates.
  • User-influenced HTML is sanitized; unsafe image URLs are blocked at render time.
  • Payload and block count limits apply (see server env: PDF_MAX_PAYLOAD_KB, etc.).
  • Plan limits (templates, PDFs/month) apply per billing tier. See Pricing.

Troubleshooting

401 Unauthorized
Missing key, wrong key format, or revoked key. Confirm the header is Bearer df_….
404 Template not found
Template ID is wrong or belongs to another account. Copy the ID from the builder URL.
Empty fields in PDF
JSON path mismatch. Compare builder sample JSON with your API payload. Run AI audit in the builder to catch bad paths.
Generation timeout
Large tables or slow hosting. Reduce rows, simplify blocks, or retry. Puppeteer needs headless Chromium on the server.
CORS errors from browser
Call the API from your backend or automation only, not from Bubble/Webflow page JavaScript. See No-code integrations.
Bubble / Make returns 401
API key not sent, marked public by mistake, or revoked. Re-create the key and update the connector secret.
PDF missing fields from no-code app
JSON field names don't match template paths. Compare Webflow/Bubble field mapping to builder sample JSON.