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

# Broadcast templates

> Write the content of a broadcast as immutable template versions. Learn how publishing works, how to personalize content with contact properties and declared variables, and which content freezes when you send.

A template holds the content of your broadcasts. The content itself lives in versions, and a broadcast sends one specific version.

<Note>
  Templates need an API key with the `broadcast` permission. See [Set up Broadcast](/docs/guides/broadcast-setup#api-key-permissions).
</Note>

## Templates and versions

A template is a named container. You create it with a name and add content by creating versions. Renaming a template does not affect its versions.

| Object | Status | Meaning |
| - | - | - |
| Template | `draft` | No version has been published yet. |
| Template | `published` | At least one version has been published. A template never returns to `draft`. |
| Version | `draft` | Content that is not the active version. |
| Version | `active` | The version that new broadcasts pick up. A template has at most one active version. |

A version holds:

| Field | Required | Description |
| - | - | - |
| `subject` | Yes | The subject line. It cannot be empty and holds up to 200 characters. |
| `html` | Yes | The HTML body. It cannot be empty. |
| `text` | No | The plain-text body. When you omit it or leave it blank, the message has no plain-text part. |
| `variables` | No | Variables the content can reference, at most 20. See [Declared variables](#declared-variables). Fixed once the version is created. |

A version is immutable. You cannot edit or delete it once it exists. To change the content, create a new version. Creating a version does not deduplicate. Sending the same request twice creates two versions.

You can read the stored HTML and text of a version. Each field comes back as a short-lived download link, or as `absent` when the field was never stored, or as `unavailable` when it cannot be read right now.

## Publish a version

Publishing checks the content and makes the version the active one of its template. The previous active version goes back to `draft`. It is not lost, and you can publish it again.

Publishing refuses a version with a `422` response when the content breaks one of these rules, checked in this order:

* The subject, the HTML, and the text contain no unsupported `{{...}}` construct. The error code is `template_version_placeholder_unsupported`. See [Personalization](#personalization) for what counts as supported.
* The HTML contains the [unsubscribe token](/docs/guides/broadcast-unsubscribe#the-unsubscribe-token). When the text body is not blank, it contains the token too. The error code is `template_version_unsubscribe_placeholder_missing`.
* The subject, HTML, and text together stay under 750 KB. The error code is `template_version_too_large`.
* The content references at most 20 distinct contact properties. The error code is `template_version_too_many_properties`.
* Every bare variable token is declared by the version. The error code is `template_version_undeclared_variable`.
* Every referenced contact property, other than `email`, has a matching definition. The error code is `template_version_undefined_property`.

Publishing a version that is not a `draft` fails with a `409` response. If two publications for the same template race, the one that finishes second fails with a `409` response and you can retry it.

## Personalization

Broadcast content can reference three kinds of tokens, all written `{{...}}`:

| Token | Example | Where it's valid |
| - | - | - |
| A contact property | `{{contact.PlanName}}` | Subject, HTML, text |
| The recipient's address | `{{contact.email}}` | Subject, HTML, text |
| A declared variable | `{{promo}}` | Subject, HTML, text |
| The unsubscribe link | `{{system.unsubscribeUrl}}` | HTML, text only |

Any other construct, such as a flat token, a Handlebars helper or block, a comment, a partial, triple braces, or a namespace keyword in the wrong letter case, is unsupported. Nuntly refuses it when you publish, with `template_version_placeholder_unsupported`. If such a construct reaches a send some other way, for example from content published before personalization existed, Nuntly strips it before rendering rather than failing the recipient.

### Contact properties

Write `{{contact.PropertyName}}` using the exact name and letter case of a [contact property definition](/docs/guides/broadcast-segments#contact-properties) of your organization. `{{contact.email}}` always works and renders the recipient's address; it's the only fixed contact field a token can read.

* The name is matched with its exact letter case. `{{contact.Plan}}` and `{{contact.plan}}` read two different properties if your organization defines both.
* At publish time, Nuntly checks that every referenced name, other than `email`, has a matching definition. An undefined name is refused with `template_version_undefined_property`.
* A version can reference at most 20 distinct contact properties across the subject, HTML, and text. More is refused with `template_version_too_many_properties`.
* When a recipient has no value for a property, Nuntly renders the property definition's default, or a typed empty value (an empty string or `0`) when there's no default. When the organization no longer defines the property at send time, Nuntly renders an empty string.

### Declared variables

A version can declare up to 20 variables: values that vary per broadcast rather than per recipient, such as a promo code or an event date. Declare them alongside `subject`, `html`, and `text` when you create the version.

| Field | Required | Description |
| - | - | - |
| `name` | Yes | 1 to 64 letters, digits, or underscores, with at least one letter or underscore. Matched with its exact letter case. Cannot be `contact`, `system`, or one of a small set of reserved words (`this`, `else`, `if`, `unless`, `each`, `with`, `lookup`, `log`, `helperMissing`, `blockHelperMissing`, `true`, `false`, `null`, `undefined`). |
| `type` | Yes | `string`, `number`, or `boolean`. |
| `default` | No | A value of the declared type, used when a broadcast supplies none. A string default stays under 1 KB serialized. |

Reference a declared variable in content as a bare token, with no namespace prefix, for example `{{promo}}`. Declarations are fixed once the version is created: you cannot add, remove, or change one afterward. Every bare token in the content must match a declared name, or publishing is refused with `template_version_undeclared_variable`. A declared variable that no part of the content references is accepted; it just goes unused.

Creating a version with an invalid declaration set is refused with a `422` response:

| Code | Cause |
| - | - |
| `template_version_variable_limit_reached` | More than 20 declarations. |
| `template_version_variable_name_invalid` | The name doesn't match the shape rule above, or is reserved. |
| `template_version_variable_duplicate` | The same name declared twice. |
| `template_version_variable_default_type_mismatch` | The default's kind doesn't match the declared type. |
| `template_version_variable_default_too_large` | A string default serializes to more than 1 KB. |

A broadcast supplies the values for these variables when you create or edit it. See [Personalization variables](/docs/guides/broadcast-sending#personalization-variables).

## What a broadcast sends

A broadcast is bound to one version of a template. These rules decide which one.

* When you create a broadcast with a template, Nuntly binds it to the version that is active at that moment. When the template has no active version yet, the binding stays empty.
* Publishing a new version does not change the version of broadcasts that are already bound. While a broadcast is `draft` or `scheduled`, name the template on it again to bind the version that is active now.
* When the binding is still empty as you send, Nuntly binds the active version of the template at the moment the broadcast is accepted. For a scheduled broadcast, that moment is when the schedule fires.
* When you send, Nuntly checks the bound version again against the publication rules above, together with the subject of the broadcast. A failure returns a `422` response and the broadcast is not sent.
* A version that has since been replaced as the active version still sends when a broadcast is bound to it. Its content does not change.
* The subject of the broadcast wins when you set one. Otherwise the subject of the bound version is used.

The content freezes once the broadcast is accepted, which is when its status becomes `queued`. From then on the template, the version, the subject, the sender address, the reply-to address, the segment, and the topic of the broadcast can no longer change. Only a `draft` or `scheduled` broadcast can be edited. See [Create and send a broadcast](/docs/guides/broadcast-sending).

## Delete a template

Deleting a template also deletes its versions. Nuntly refuses with a `409` response while any broadcast, in any status, references the template or one of its versions. A broadcast that has been accepted cannot be deleted, so the template of a `queued`, `sending`, `paused`, or `sent` broadcast cannot be deleted either.

## Operations

| Operation | Request |
| - | - |
| Create a template | `POST /templates` |
| List templates | `GET /templates` |
| Retrieve a template | `GET /templates/{templateId}` |
| Rename a template | `PATCH /templates/{templateId}` |
| Delete a template | `DELETE /templates/{templateId}` |
| Create a version | `POST /templates/{templateId}/versions` |
| List versions | `GET /templates/{templateId}/versions` |
| Retrieve a version | `GET /templates/{templateId}/versions/{versionId}` |
| Read the content of a version | `GET /templates/{templateId}/versions/{versionId}/content` |
| Publish a version | `PATCH /templates/{templateId}/versions/{versionId}/publish` |

## Next steps

<CardGroup cols={2}>
  <Card title="Create and send a broadcast" icon="send" href="/docs/guides/broadcast-sending">
    Bind a template to a broadcast and send it
  </Card>

  <Card title="Unsubscribe and suppression" icon="mail-x" href="/docs/guides/broadcast-unsubscribe">
    The unsubscribe link that the placeholder becomes
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.