PDF templates

Import a PDF

Turn an existing PDF into a variable template.

A PDF template is any existing PDF — an exported invoice, a scanned form, a Canva certificate — with some of its text marked as {{variables}}. Fill it with data through one API call and the design stays pixel-identical; only the marked spans change. No HTML to rewrite, no font to re-embed.

Two template systems

This is not the HTML/blocks template system. That one renders a design you authored in HTML. A PDF template starts from a PDF that already exists and reuses its exact layout.

The fastest path is the dashboard editor: upload the PDF, click a text span, turn it into a variable, and save. The editor detects the span geometry, colour and font for you, so a later fill masks the original text and redraws your value in place.

Once saved, the template gets an id and a slug and appears in your templates list.

The programmatic way

You can also create a template with the API. A variable maps a name to a span located by span_id — the stable element id returned by the perception layer. So the flow is: perceive the PDF, pick the spans, create.

Perceive the PDF

POST /v1/pdf/perceive returns every text element with a stable id, its text, bbox and style. Pick the ones you want to turn into variables.

const doc = await client.pdf.perceive(pdfBytes, { detail: "full" });

Create the template

POST /v1/pdf-templates stores the base PDF (base64) plus the variable map. Each variable carries the span_id and, ideally, the geometry/style from perceive so the fill can mask-and-redraw on any font.

PDF=$(base64 -w0 invoice.pdf)     # macOS: base64 -i invoice.pdf

curl -X POST https://api.pdf-forge.dev/v1/pdf-templates \
  -H "Authorization: Bearer $PDFFORGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"name\": \"Invoice\",
    \"pdf\": \"$PDF\",
    \"variables\": [
      { \"name\": \"client_name\", \"span_id\": \"p1:span:42\", \"default\": \"ACME Corp\" },
      { \"name\": \"total\", \"span_id\": \"p1:span:88\", \"default\": \"250,000 FCFA\" }
    ]
  }"
const { id, slug } = await client.pdfTemplates.create({
  name: "Invoice",
  pdf: pdfBytes,
  variables: [
    { name: "client_name", span_id: "p1:span:42", default: "ACME Corp" },
    { name: "total", span_id: "p1:span:88", default: "250,000 FCFA" },
  ],
});

The response is { "id": "...", "slug": "..." } (HTTP 201). Store the id — it is what you render against.

Let an agent do it

The MCP server ships a create_pdf_template tool that runs this whole loop — perceive, pick spans, resolve geometry, create — from a natural-language prompt. It fills in span_id, bg, color, size, font and member_ids from the perception automatically.

List your templates

GET /v1/pdf-templates returns your templates (metadata only — no PDF bytes):

const templates = await client.pdfTemplates.list();
// [{ id, name, slug, variables, page_count, size_bytes, updated_at }]

Next steps

On this page