Skip to main content

template.json

template.json describes a template's display name, its editable fields, and the capabilities it supports. Every template has one, and you can write it in two places:

WhereHow
In AllegroOpen the template, go to the Options tab, and click Edit template.json. Apply updates the template's name, Fields, and Options tabs; save the template to keep the changes. See Editing template.json.
In a GitHub repositoryPut template.json in the template's folder alongside index.html. On sync, name becomes the template's title and each field becomes an editable input. The file is read-only in Allegro: View template.json shows it as last synced.

The Local Template Preview reads the same file. The REST API's get template endpoint and the MCP get-template tool return it as template_json.

A machine-readable JSON Schema is published for editor autocompletion and validation. Reference it from your file with $schema:

{
"$schema": "https://docs.allegroaudience.com/template.schema.json",
"name": "Newsletter Signup",
"fields": [
{
"slug": "headline",
"type": "text",
"label": "Headline",
"default_value": "Stay in the know"
}
]
}

Top-level properties​

PropertyTypeRequiredDescription
$schemastringNoThe schema URL, for editor autocompletion. Allegro adds it to every file it writes.
namestringYesDisplay name (title) of the template, trimmed. A synced template without one is named after its folder (plan-picker → "Plan Picker").
fieldsarrayYesThe editable fields exposed by the template, in the order editors see them. May be empty.
supportsarrayNoCapabilities the template declares. See Supports.
plansarrayNoPreview only. Sample plans for the local preview. Ignored on sync and when applied in Allegro.

Any other top-level property is allowed but not stored. When you apply the file in Allegro, the editor lists the properties it will leave out.

Field properties​

PropertyTypeRequiredDescription
slugstringYesPlaceholder identifier. Lowercase letters, numbers, -, and _ only (^[a-z0-9_-]+$).
typestringYesOne of text, textarea, richtext, number, checkbox, enum, group.
labelstringNoName shown to editors. Defaults to the slug in words (faq_sections → "Faq sections").
descriptionstringNoHelp text shown under the label.
tabstringNoTop-level fields only. The tab the field appears in when editors fill it in, up to 60 characters. See Tabs.
formatsarrayNorichtext only. Any of bold, italic, link, bulleted_list, numbered_list; all five when omitted.
repeatablebooleanNoLets editors enter a list of values instead of one. A group is always repeatable.
autocompletestringNotext fields that aren't repeatable only. An autocomplete source whose values editors pick from. See Autocomplete.
optionsarrayFor enumAt least one choice: a string (used as both value and label) or { "value", "label" }, where label defaults to value.
fieldsarrayFor groupThe subfields of a group. Subfields take every property except tab and default_value, and can be groups themselves up to three levels deep.
default_valueanyNoValue an interaction uses until it saves its own, and the preview editor's initial value. Use an array for a repeatable field.
Default values on interactions

An interaction action that uses the template renders default_value for any field it has no saved value for, including fields added to the template later. A saved value wins, even an empty one. A checkbox default of true or false is stored as the text "true" or "false", and a default that doesn't match the field's shape (an array on a single field, or text on a repeatable one) is dropped on sync.

Field types​

TypeEditors seeValue
textSingle-line text inputThe text
textareaMulti-line text inputThe text
richtextEditor with the field's formatsCleaned HTML
numberNumber inputThe number, as text
checkboxToggle"true" or "false"
enumSelect of the field's optionsThe chosen option's value
groupA list of items, each with one input per subfieldA list of objects keyed by subfield slug

text, number, checkbox, and enum values are limited to 200 characters; textarea and richtext values to 10,000. A repeatable field holds up to 50 items. Every value except richtext is inserted into the page as escaped text. A richtext value keeps only paragraphs, line breaks, and its allowed formats, and links must use http, https, or mailto.

Repeatable fields and groups​

Mark a field repeatable to let editors add as many values as they need, such as a list of links. Use a group when each item needs several values, such as newsletters that each have a title, image, and ID. A group's subfields can be repeatable, and can be groups themselves, up to three levels deep (a top-level field, a group inside it, and a group inside that).

{
"fields": [
{
"slug": "links",
"type": "text",
"label": "Links",
"repeatable": true
},
{
"slug": "newsletters",
"type": "group",
"label": "Newsletters",
"fields": [
{ "slug": "id", "type": "text", "label": "List ID" },
{ "slug": "title", "type": "text", "label": "Title" },
{ "slug": "image", "type": "text", "label": "Image URL" },
{
"slug": "frequency",
"type": "enum",
"options": ["daily", "weekly"]
}
]
}
]
}

Loop over a repeatable field in the template HTML with {% for item in slug %}…{% endfor %}. See Repeatable fields for the full syntax.

Tabs​

Set tab on top-level fields to split a long list of fields into tabs where editors fill them in: the interaction editor's template fields drawer and the template editor's Fields tab. Fields that share a tab value appear together, so a template with a header, an FAQ, and a contact section can give each its own tab.

{
"name": "Help Center",
"fields": [
{ "slug": "intro", "type": "textarea", "label": "Intro" },
{ "slug": "title", "type": "text", "label": "Title", "tab": "Header" },
{
"slug": "faq",
"type": "group",
"label": "Questions",
"tab": "FAQ",
"fields": [
{ "slug": "question", "type": "text" },
{ "slug": "answer", "type": "richtext" }
]
},
{
"slug": "subtitle",
"type": "text",
"label": "Subtitle",
"tab": "Header"
}
]
}

Editors see three tabs: General (intro), Header (title, then subtitle), and FAQ (faq).

  • Fields without a tab go in a General tab, which always comes first.
  • The other tabs follow in the order their first field appears in fields. Within a tab, fields keep their order from fields.
  • Tab names are matched exactly after trimming spaces, so "FAQ" and "faq" make two tabs.
  • A tab name can be up to 60 characters.
  • Only top-level fields take a tab. A group's subfields always appear inside the group, and the sync ignores tab on a subfield.

Tabs only arrange the editor. They don't change how fields render, and you reference a field by its slug whichever tab it's in.

Autocomplete​

Set autocomplete on a text field to let editors pick its value from a list that one of your packages provides, such as campaign IDs from a fundraising integration, while still letting them type their own. The value is the source's name, package/key:

{
"slug": "campaign",
"type": "text",
"label": "Campaign",
"autocomplete": "my-package/campaign-ids"
}

To find a source's name, pick it under Autocomplete on the field in the template editor's Fields tab, then open Edit template.json.

  • It works on a text field at any depth, including group subfields, as long as the field isn't repeatable.
  • If the source's package isn't enabled, editors get a plain text input. The source stays on the field and comes back when the package is enabled.
  • The field's value is whatever editors enter, so treat it like any other text value in your template.

Supports​

supports lists the capabilities a template declares. plans is the only one today: it marks the template as showing plans from an offer.

{
"name": "Plan Picker",
"supports": ["plans"],
"fields": []
}

When a template supports plans:

  • Every interaction that uses the template must choose an offer. The interaction editor shows an Offer picker for it, and saving without one fails.
  • No field may use the slug plans. The sync skips a field with that slug and records a warning in the sync log.

Values other than plans are ignored on sync and recorded as warnings, so a typo doesn't stop the rest of the template from syncing.

See Plans for how the template renders the offer's plans in HTML, Alpine.js, and index.js.

Validation​

Allegro checks the file differently depending on where it comes from.

In Allegro, Apply checks the file against the JSON syntax and the schema, lists every error with its line number, and changes nothing until they are all fixed. Saving the template then runs the same checks as the Fields tab, such as the 60-character tab limit.

From GitHub, the sync keeps what it can, so one bad field doesn't stop the template from syncing. Skipped fields, invalid autocomplete sources, and unknown supports values are listed as warnings on the sync status in GitHub Sync settings.

ProblemWhat the sync does
File missing or not valid JSONSyncs the template with no fields, named after its folder
A field's slug doesn't match ^[a-z0-9_-]+$Skips the field
A field's type is unknown, or a group is nested too deepSkips the field
An enum field with no valid optionsSkips the field
A group with no valid subfieldsSkips the group; invalid subfields are skipped alone
A field with the slug plans on a template that supports plansSkips the field
An unknown supports valueIgnores the value
An autocomplete that isn't a package/key nameDrops the source and keeps the field
An autocomplete on a field that isn't a single text fieldDrops the source
A name another template in the repository already usesSyncs both, with a warning
A default_value that doesn't fit the fieldDrops the default

Files Allegro writes​

When Allegro generates template.json for a template built in Allegro, it adds $schema, leaves out properties that hold their default (an empty description, repeatable on a group), and writes an enum option whose label matches its value as a plain string. Copying that file into a GitHub repository syncs back to the same template.

In local preview​

Local Template Preview reads template.json and renders an editor input per field in its sidebar, seeded with default_value. Repeatable fields and groups get Add item, reorder, and Remove buttons. Seed them with an array:

{
"slug": "newsletters",
"type": "group",
"fields": [{ "slug": "title", "type": "text" }],
"default_value": [
{ "title": "Morning Briefing" },
{ "title": "Weekend Reads" }
]
}

The local preview renders a plans template with two sample plans. To preview your own, add a top-level plans list in the shape a template receives. The sync ignores it. See Previewing Plans.

{
"name": "Plan Picker",
"supports": ["plans"],
"fields": [],
"plans": [
{
"id": "annual",
"name": "Annual",
"formatted_price": "$99.00",
"duration_label": "1 year",
"fields": { "badge": "Best value" }
}
]
}

Complete example​

{
"$schema": "https://docs.allegroaudience.com/template.schema.json",
"name": "Newsletter Signup",
"fields": [
{
"slug": "headline",
"type": "text",
"label": "Headline",
"default_value": "Stay in the know"
},
{ "slug": "intro", "type": "textarea", "label": "Intro" },
{
"slug": "theme",
"type": "enum",
"label": "Theme",
"options": [
{ "value": "light", "label": "Light" },
{ "value": "dark", "label": "Dark" }
],
"default_value": "light"
},
{
"slug": "newsletters",
"type": "group",
"label": "Newsletters",
"fields": [
{ "slug": "id", "type": "text", "label": "List ID" },
{ "slug": "title", "type": "text", "label": "Title" }
],
"default_value": [{ "id": "morning", "title": "Morning Briefing" }]
},
{
"slug": "show_privacy_note",
"type": "checkbox",
"label": "Show privacy note"
}
]
}