> ## Documentation Index
> Fetch the complete documentation index at: https://docs.craftkit.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Concepts

> Templates, versions, variables, manifests, and the render pipelines — the mental model behind every API call.

## Template

A **template** is a versioned document blueprint inside a project, addressed by a URL-safe
**slug** (unique per project). You render against a slug: `POST /v1/templates/:slug/render`.

## Version

Publishing a template snapshots an immutable **version** (`currentVersionNumber`). Renders use
the current published version unless you pin one with `options.versionNumber`. A template with no
published version cannot be rendered (`no_published_version`).

## Variable

A typed merge field. Each variable has a dot-path `key` (`customer.name`), a `dataType`, and a
`required` flag.

| `dataType`           | Accepts at render time                                           |
| -------------------- | ---------------------------------------------------------------- |
| `text`, `longtext`   | any string                                                       |
| `number`, `currency` | number (numeric strings are coerced)                             |
| `date`, `datetime`   | ISO string or Date                                               |
| `boolean`            | boolean (`"true"`/`"false"` coerced)                             |
| `image`, `url`       | an **http(s) URL** (`z.string().url()` — data-URIs are rejected) |
| `email`              | a valid email                                                    |

See [Variables & loops](/guides/variables-and-loops) for dot-path nesting and arrays.

## Manifest

The **variable manifest** is the contract a render payload must satisfy:
`{ variables: VariableDefinition[], loops: LoopDefinition[] }`. It is **auto-extracted from the
template at publish time** — you cannot POST a manifest directly. Read it with
[`GET /v1/templates/:slug`](/api-reference/get-template).

<Warning>
  The render endpoint validates `data` against the manifest and **strips any key that is not in
  the manifest** before the worker runs. If a key does not bind, the value is silently dropped —
  this is the most common cause of a "missing" field. Read the manifest and match it exactly.
</Warning>

## Render

A single execution: input data + status + asset. Renders are **asynchronous** — enqueued on a
queue, processed by a worker, uploaded to object storage. Status moves
`queued → rendering → succeeded | failed`. See [Render lifecycle](/guides/render-lifecycle).

## Render pipelines

Not every template renders the same way. The worker chooses one of **three** pipelines based on
the published version's content, and they differ in what they can do (loops, dynamic images).
This choice drives whether arrays and signature images work — read
[Render pipelines](/guides/render-pipelines) before authoring a data-heavy template.

<CardGroup cols={3}>
  <Card title="Document mode" icon="file-lines">
    Block layout via `@react-pdf`. No loops, static images.
  </Card>

  <Card title="Canvas (Handlebars)" icon="brush">
    HTML → Puppeteer. Loops and dynamic images.
  </Card>

  <Card title="PDF overlay" icon="stamp">
    Fields stamped onto an uploaded base PDF via pdfme.
  </Card>
</CardGroup>
