---
title: "Create Template"
method: POST
path: "/templates"
tags: ["Templates"]
---

# Create Template

`POST /templates`

## Request

- Base URL: `https://app.lettr.com/api`
- URL: `https://app.lettr.com/api/templates`
- Auth: HTTP bearer

Create a new email template with HTML or Topol editor JSON content. Automatically creates and publishes a template version with extracted merge tags.

## Request body

- CreateTemplateRequest: Request to create a new email template. Provide either `html` for custom HTML templates or `json` for Topol visual editor templates.
  - `name` string, required: Name of the template
  - `project_id` integer: Project ID to create the template in. If not provided, uses the team's default project.
  - `folder_id` integer: Folder ID to create the template in. Must belong to the same module as `purpose`. If not provided, the first folder of that module is used, and one is created when the project has none.
  - `html` string: HTML content for custom HTML templates. Required if `json` is not provided. Mutually exclusive with `json`.
  - `json` string: JSON content for Topol visual editor templates. Required if `html` is not provided. Mutually exclusive with `html`.
  - `purpose` 'transactional' | 'campaign': Module the template belongs to. `transactional` templates are the ones you send single emails with; `campaign` templates are the ones the campaign builder can pick. Defaults to `transactional`.

## Response `201`

Template created successfully

- CreateTemplateResponse: Response after successfully creating a template
  - `message` string, required: Human-readable response message
  - `data` CreatedTemplateView, required: View of a newly created template
    - `id` integer, required: Unique identifier for the template
    - `name` string, required: Name of the template
    - `slug` string, required: URL-friendly identifier for the template
    - `project_id` integer, required: ID of the project containing this template
    - `folder_id` integer, required: ID of the folder containing this template
    - `purpose` 'transactional' | 'campaign', required: Module the template belongs to. `transactional` templates are the ones you send single emails with; `campaign` templates are the ones the campaign builder can pick.
    - `preparation_status` 'pending' | 'ready' | 'failed', required: How far the template has got through preparation. Creating or updating a template through the API defers image migration and HTML rendering to a background job, so the template is `pending` until that finishes. On a create with JSON there is no HTML at all yet - the editor works (it reads the JSON) but sending and the screenshot do not. On an update the previous render stays in place, so the template remains sendable, but it is still serving the *old* content until this reads `ready`. `failed` means preparation exhausted its retries and will not become ready on its own. A template created from raw HTML is `ready` immediately.
    - `active_version` integer, required: Version number of the active template version
    - `merge_tags` MergeTagView[], required: List of merge tags extracted from the template content
      - `key` string, required: The merge tag key/name used in templates
      - `required` boolean, required: Whether this merge tag is required when sending emails
      - `type` 'text' | 'number' | 'image' | 'button': The data type of the merge tag (only present for loop children)
      - `children` MergeTagChild[]: Child merge tags for loop blocks. Each child represents a field available within the loop iteration.
        - `key` string, required: The child merge tag key/name
        - `type` 'text' | 'number' | 'image' | 'button': The data type of the child merge tag
    - `created_at` string, date-time, required: When the template was created

## Other responses

- `401`: Unauthorized - Missing or invalid API key
- `404`: Project or folder not found
- `422`: Validation error
- `500`: Server error
- `503`: Service unavailable - the API key could not be verified, so the request was not processed. This does not mean the key is invalid; retry after the delay given in the Retry-After header.

---

[API](https://skmtc.dev/lettr/apis/lettr-api.md) · [All operations](https://skmtc.dev/lettr/apis/lettr-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lettr/apis/lettr-api/revisions/48ef0dac1ebd?raw)
