---
title: "Template Basics"
canonical_url: https://docs.zvid.io/docs/templates/template-basics/
source: docs/templates/template-basics.md
content_revision: 6338386a1dd87e4a
---

# Template Basics

Templates turn one project into many videos: author the design once with
**variables**, then render it with different data every time — one render at a
time or [batches](https://docs.zvid.io/docs/automation/bulk-rendering/) within your plan's item limit.

## Variables and placeholders

Declare defaults under `variables` and reference them with `{{name}}`.
The following is a **project payload**, placed under `payload` in a render or
template-create request:

```json
{
  "variables": {
    "title": "Aurora Sneakers",
    "accent": "#a78bfa",
    "price": "$129"
  },
  "visuals": [
    {
      "type": "TEXT",
      "html": "<div class=\"name\">{{title}}</div><div class=\"price\">{{price}}</div>",
      "customCode": {
        "css": ".price { color: {{accent}}; }"
      }
    }
  ]
}
```

- Placeholders work in text, HTML, CSS, URLs, colors, and numeric fields.
- `{{name.path.to.field}}` reaches into object and array variables
  (`{{product.title}}`, `{{sizes.0}}`).
- Variables can be strings, numbers, booleans, arrays, or objects.
- Scenes can declare their own `variables` block, which shadows project
  variables inside that scene.
- Unresolvable placeholders are **rejected at submit time** with a field-level
  validation error — you can't accidentally ship `{{title}}` on screen.
- An exact placeholder such as `"{{price}}"` preserves the resolved value's
  type; surrounding text produces a string. Validate the resolved output,
  especially when variables control dimensions, colors, or URLs.

## Rendering with data

Submit `template` **or** `payload` (never both) to the render endpoint.
Request-time `variables` override the declared defaults:

```bash
curl -X POST https://api.zvid.io/api/render/api-key \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template": "tpl_xxxxxxxxxxxxxxxxxxxx",
    "variables": { "title": "Nimbus Backpack", "accent": "#f59e0b", "price": "$89" },
    "overrides": { "name": "nimbus-backpack" }
  }'
```

- `template` — a stored template id (`tpl_…`). Save one from
  [the editor](https://docs.zvid.io/docs/editor/templates/) (**Save → Save as template**) or via
  `POST /api/templates`; find ids on the
  [dashboard's Templates page](https://docs.zvid.io/docs/dashboard/templates-and-bulk/).
- `variables` — per-render values merged over the template's defaults.
- `overrides` — output knobs applied before variable resolution: `name`,
  `resolution`, `width`, `height`, `outputFormat`, `frameRate`, `backgroundColor`, and the
  [image-render](https://docs.zvid.io/docs/rendering-images/) fields (`snapshotTime`, `quality`,
  `transparent`).

You can also send a full `payload` containing `variables` — templates don't
have to be stored to use placeholders.

Only the listed output fields are allowed in a render request's `overrides`.
It cannot replace `visuals`, `scenes`, `duration`, or project `type`.
Overriding width or height without a resolution switches to `resolution: "custom"`.
For stored video templates, every scene must resolve to an explicit positive
`duration`; scene auto-fit (`-1` or omitted) is not supported on this path.

## Save and preview a template

Create a template with `POST /api/templates`, an API key, JSON Content-Type,
and a body containing `name` and `payload`. Defaults must make the template
valid at save time. For example, this is a complete request body:

```json
{
  "name": "Greeting",
  "payload": {
    "duration": 3,
    "variables": { "title": "Hello" },
    "visuals": [
      { "type": "TEXT", "text": "{{title}}", "position": "center-center" }
    ]
  }
}
```

Read the new ID from `template.id` in the create response. To inspect a new
dataset **without rendering or spending credits**, call:

```bash
curl -X POST https://api.zvid.io/api/templates/TEMPLATE_ID/preview \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "variables": { "title": "Hello, Cairo" } }'
```

Replace `TEMPLATE_ID` with the returned `tpl_…` ID. Preview returns HTTP 200
with `project` (resolved, validated project JSON) and `stats` (resolution
statistics). It returns **no job ID or media URL**. Use
[Validate and estimate](https://docs.zvid.io/docs/validate-and-estimate/) for `creditsRequired`,
then the render endpoint to produce media.

### Same template, two datasets

The same visual design rendered with two variable sets. These recorded fixtures
include their full project settings and additional card styling:


```json
{
  "name": "docs-template-var-a",
  "width": 960,
  "height": 540,
  "duration": 5,
  "backgroundColor": "#140b2e",
  "variables": {
    "title": "Aurora Sneakers",
    "accent": "#a78bfa",
    "price": "$129"
  },
  "visuals": [
    {
      "type": "TEXT",
      "html": "<div class=\"card\"><div class=\"name\">{{title}}</div><div class=\"price\">{{price}}</div></div>",
      "position": "center-center",
      "enterBegin": 0,
      "exitEnd": 5,
      "customCode": {
        "css": ".card { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 40px 80px; background: rgba(255,255,255,0.06); border: 2px solid {{accent}}; border-radius: 24px; } .name { color: #ffffff; font-family: Montserrat; font-size: 56px; font-weight: 800; } .price { color: {{accent}}; font-family: Poppins; font-size: 44px; font-weight: 700; animation: pop 1.4s ease-in-out infinite; } @keyframes pop { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } }",
        "animationDuration": 1.4
      }
    }
  ]
}
```

variables: { "title": "Aurora Sneakers", "accent": "#a78bfa", "price": "$129" }

[Watch rendered example](https://cdn.zvid.io/library/docs/template-var-a.mp4)


```json
{
  "name": "docs-template-var-b",
  "width": 960,
  "height": 540,
  "duration": 5,
  "backgroundColor": "#140b2e",
  "variables": {
    "title": "Nimbus Backpack",
    "accent": "#f59e0b",
    "price": "$89"
  },
  "visuals": [
    {
      "type": "TEXT",
      "html": "<div class=\"card\"><div class=\"name\">{{title}}</div><div class=\"price\">{{price}}</div></div>",
      "position": "center-center",
      "enterBegin": 0,
      "exitEnd": 5,
      "customCode": {
        "css": ".card { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 40px 80px; background: rgba(255,255,255,0.06); border: 2px solid {{accent}}; border-radius: 24px; } .name { color: #ffffff; font-family: Montserrat; font-size: 56px; font-weight: 800; } .price { color: {{accent}}; font-family: Poppins; font-size: 44px; font-weight: 700; animation: pop 1.4s ease-in-out infinite; } @keyframes pop { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } }",
        "animationDuration": 1.4
      }
    }
  ]
}
```

The same template with { "title": "Nimbus Backpack", "accent": "#f59e0b", "price": "$89" }

[Watch rendered example](https://cdn.zvid.io/library/docs/template-var-b.mp4)


## Template API

| Endpoint                             | Auth           | Purpose                                          |
| ------------------------------------ | -------------- | ------------------------------------------------ |
| `GET /api/templates`                 | JWT or API key | List your templates                              |
| `POST /api/templates`                | JWT or API key | Create a template from a project                 |
| `GET /api/templates/{id}`            | JWT or API key | Fetch a template (inspect variables)             |
| `PUT /api/templates/{id}`            | JWT or API key | Update                                           |
| `DELETE /api/templates/{id}`         | JWT or API key | Archive                                          |
| `POST /api/templates/{id}/duplicate` | JWT or API key | Duplicate                                        |
| `POST /api/templates/{id}/preview`   | JWT or API key | Free dry run; returns resolved project and stats |

## Next

- [Dynamic content](https://docs.zvid.io/docs/templates/dynamic-content/) — generate scenes from arrays with
  `iterate` and show/hide content with `condition`.
- [Bulk rendering](https://docs.zvid.io/docs/automation/bulk-rendering/) — one request, many
  variable sets.
- [Variables in the editor](https://docs.zvid.io/docs/editor/templates/) — author templates
  visually.
