Skip to Content
ConceptsDesigns

Designs

A design is a reusable document layout. It is the thing you author once and generate from many times. Internally a design is a tree of pages and elements — the shape is defined by the shared pdftreejs library, so the visual editor, the API, and the renderer all agree on it.

The design tree

  • A design has one or more pages.
  • Each page holds positioned elements.
  • Element types include text, tables, images, QR codes, barcodes, and shapes.
  • You place elements with explicit coordinates. Text and table sizes are derived — a text box is measured from its content and font, a table from its grid — so a client can never produce a clipped or sprawling box.

You never hand-write the tree. You build it by issuing actions — small, validated operations like add_element and bind_variable — and ImaginePDF applies them to the design.

Authoring with actions

Every change to a design’s structure is an action of the form:

{ "type": "add_element", "args": { /* args for this action */ } }

The core model is tree + action → tree: each action does one thing (add one element, bind one variable), and a request carries an ordered list of them. They apply sequentially and atomically — if any action fails, nothing is saved and the error names the failing index.

  • POST /api/v1/designs — create a design (name + optional description). This allocates the design and returns a designId; it does not take actions.
  • PATCH /api/v1/designs/:id — apply actions (and/or rename / describe). This is where authoring happens, including the first batch on a new design.

Two conventions to know:

  • Ids are server-minted. add_element does not accept an id; give each element a unique, meaningful name ("title", "line_items") and address it by that name in later actions. The minted id (text-cfd23) comes back in the result.
  • Results echo the derived box. Each add_element result includes the element’s final { x, y, w, h } — use it to place the next element below.

The full set of available actions and their args schemas comes from the catalog:

curl https://api.imaginepdf.com/api/v1/actions \ -H "X-API-Key: $IMAGINEPDF_API_KEY"
{ "status": "success", "data": { "actions": [ { "name": "add_element", "description": "...", "args": { /* schema */ } }, { "name": "bind_variable", "description": "...", "args": { /* schema */ } } ] }, "error": null }

Actions are validated server-side by pdftreejs, strictly: unknown keys are rejected with a message that says the fix — e.g. sending position.w for a text element returns position.w is not allowed for text — width is derived; use position.maxWidth. See the Designs API for the per-type position shapes.

Reading a design back

Reads are split by cost. GET /api/v1/designs/:id returns just the metadata (enveloped):

{ "status": "success", "data": { "designId": "design_abc123", "name": "Invoice", "description": "Standard invoice template", "fileSize": 12345, "createdAt": "2026-06-08T12:00:00Z", "modifiedAt": "2026-06-08T12:00:00Z" }, "error": null }

To read the layout itself, GET /api/v1/designs/:id/tree returns the full design tree as raw JSON (this endpoint is not enveloped — the body IS the tree; its variables are part of it). See the Designs API.

From design to PDF

A design on its own is just a layout. To get a finished document you generate it — supplying values for any variables. See Variables for how binding works and Generate a PDF for the call.

Last updated on