---
title: Templates Reference
path: reference/templates
status: published
---

# Templates Reference

Endpoints for managing templates and their versions. For the guide-level walk-through, see [Templates](../tutorials/templates).

**Base path:** `/v3/templates/`
**Required permission:** `templates.read` (GET), `templates.write` (POST/PATCH/activate/deactivate/duplicate), `templates.delete` (DELETE).

## GET /v3/templates

List templates.

**Query parameters:**

| Parameter | Notes |
|-----------|-------|
| `generations` | Filter by generation: `dynamic`, `legacy` (SendGrid-compat query param) |

**Response (200):**

```json
{
  "result": [
    {
      "id": "d-abc123",
      "name": "welcome-email",
      "generation": "dynamic",
      "created_at": "2026-04-23T10:00:00Z",
      "updated_at": "2026-04-23T10:00:00Z",
      "versions": []
    }
  ]
}
```

## POST /v3/templates

Create a template.

**Request body:**

| Field | Type | Required | Notes |
|-------|------|---------|-------|
| `name` | string | Yes | Unique within tenant |
| `generation` | string | No | `dynamic` (default) or `legacy` |

**Response (201):**

```json
{
  "id": "d-abc123",
  "name": "welcome-email",
  "generation": "dynamic",
  "versions": [],
  "created_at": "2026-04-23T10:00:00Z",
  "updated_at": "2026-04-23T10:00:00Z"
}
```

## GET /v3/templates/{template_id}

Get a template with all versions.

**Response (200):**

```json
{
  "id": "d-abc123",
  "name": "welcome-email",
  "generation": "dynamic",
  "versions": [
    {
      "id": "v_01HXYZ",
      "template_id": "d-abc123",
      "name": "v1",
      "subject": "Welcome, {{name}}",
      "active": 1,
      "html_content": "<h1>Hi {{name}}</h1>",
      "plain_content": "Hi {{name}}",
      "preheader": "",
      "editor": "code",
      "created_at": "...",
      "updated_at": "..."
    }
  ]
}
```

**Errors:** 404 if template not found.

## PATCH /v3/templates/{template_id}

Update a template's metadata (name only).

**Request body:**

```json
{"name": "welcome-email-v2"}
```

**Response (200):** updated template object.

## DELETE /v3/templates/{template_id}

Delete a template and all its versions. In-flight sends referencing this template complete normally; new sends return 400.

**Response (204):** no body.

## GET /v3/templates/{template_id}/versions

List versions of a template.

**Response (200):**

```json
[
  {"id": "v_01HXYZ", "template_id": "d-abc123", "name": "v1", "active": 1, ...}
]
```

## POST /v3/templates/{template_id}/versions

Create a new version.

**Request body:**

| Field | Type | Required | Notes |
|-------|------|---------|-------|
| `name` | string | Yes | 1–255 chars |
| `subject` | string | No | ≤ 1000 chars; template-rendered |
| `preheader` | string | No | ≤ 500 chars; preview text |
| `html_content` | string | No | HTML body |
| `plain_content` | string | No | Plain-text body |
| `editor` | string | No | `code` or `design` |
| `active` | integer (0/1) | No | Activate immediately |

**Response (201):** version object.

## GET /v3/templates/{template_id}/versions/{version_id}

Get a single version.

**Response (200):**

```json
{
  "id": "v_01HXYZ",
  "template_id": "d-abc123",
  "name": "v1",
  "active": 1,
  "subject": "Welcome, {{name}}",
  "preheader": "Your welcome message",
  "html_content": "<h1>Hi {{name}}</h1>",
  "plain_content": "Hi {{name}}",
  "editor": "code",
  "created_at": "2026-04-23T10:00:00Z",
  "updated_at": "2026-04-23T10:00:00Z"
}
```

## PATCH /v3/templates/{template_id}/versions/{version_id}

Update a version's content.

**Request body:** any subset of version fields.

**Response (200):** updated version.

## DELETE /v3/templates/{template_id}/versions/{version_id}

Delete a version.

**Response (204):** no body.

**Errors:** 400 if this is the only active version (deactivate first).

## POST /v3/templates/{template_id}/versions/{version_id}/activate

Make this version the active one (deactivates any currently-active version).

**Response (200):** the now-active version.

## POST /v3/templates/{template_id}/versions/{version_id}/deactivate

Deactivate this version. The template then has no active version — subsequent sends with the template_id will fail until another version is activated.

**Response (200):** the deactivated version.

## POST /v3/templates/{template_id}/versions/{version_id}/duplicate

Copy a version. The copy is inactive by default.

**Request body:**

| Field | Type | Notes |
|-------|------|-------|
| `name` | string | Name for the new version (required if original name is already taken) |

**Response (201):** the duplicated version.

## Handlebars syntax

ScaiSend uses [chevron](https://pypi.org/project/chevron/) for dynamic templates. Supported constructs:

- Variables: `{{name}}`, `{{{raw_html}}}`
- Conditionals: `{{#if cond}}...{{else}}...{{/if}}`
- Iteration: `{{#each items}}...{{this.field}}...{{/each}}`

Helpers: `uppercase`, `lowercase`, `truncate`, `default`, `length`, `formatDate`, `equals`, `greaterThan`, `lessThan`, `and`, `or`.

See [Templates guide](../tutorials/templates#template-syntax) for examples.

## Related

- [Templates (guide)](../tutorials/templates)
- [Sending Mail](../tutorials/sending-mail) — using `template_id` on a send.
