Managing templates via the API

The Flow Templates API lets you manage page and ballot templates programmatically — list, create, update, clone, and more — without using the UI.

All examples below use cURL. Replace YOUR_API_TOKEN with your API key and https://app.example.com with your instance URL.

How fields work

Fields are the core of what makes a template reusable. A template's body_html contains Liquid tags like {{ template.heading }}, and the fields array defines what those tags are — their type, label, default value, and how they appear in the page builder.

When someone creates a page from your template, each field becomes an editable input. The values they enter get substituted into the HTML via Liquid at render time.

Example: a template with fields

Here's a complete template that has a heading, an intro paragraph, and an optional hero image:

Body HTML:

<div class="header">
  <h1>{{ template.heading }}</h1>
</div>
<div class="content">
  {% if template.heroImage != blank %}
    <div class="hero">{{ template.heroImage }}</div>
  {% endif %}
  <p class="intro">{{ template.introText }}</p>
  <surveyform></surveyform>
</div>

Fields:

[
  {
    "slug": "heading",
    "label": "Page Heading",
    "questionType": "text",
    "wysiwyg": true,
    "defaultValue": "Take our survey",
    "translatable": true,
    "showInWizard": true
  },
  {
    "slug": "heroImage",
    "label": "Hero Image",
    "questionType": "image",
    "image": true,
    "required": false,
    "showInWizard": true
  },
  {
    "slug": "introText",
    "label": "Introduction",
    "questionType": "paragraph",
    "wysiwyg": true,
    "defaultValue": "Thanks for taking the time to fill out our survey.",
    "translatable": true
  }
]

Notice how each field's slug matches a {{ template.slug }} tag in the HTML. The heading field has wysiwyg: true so it can be edited inline in the page builder preview. The heroImage field is optional (required: false) and the HTML uses a Liquid {% if %} block to hide it when empty.

Field properties

Each field requires:

  • slug — unique identifier, must be camelCase (this is what you reference in HTML as {{ template.slug }})
  • label — display name shown when editing
  • questionType — one of: text, url, paragraph, select, checkbox, image

Common optional properties:

  • defaultValue — pre-filled value when a page is created from this template
  • wysiwyg — if true, the field is editable directly in the page builder preview
  • setup — if true, shown in the page builder's setup tab instead of the editor
  • showInWizard — if true, shown in the initial page creation wizard
  • translatable — if true, the value can differ across languages
  • required — whether the field must be filled in (default: true)
  • image — if true, the value is rendered as an image
  • description — help text shown when editing the field
  • options — for select fields, an array of { "value": "...", "label": "..." } choices

Field types

TypeDescriptionExample use
textSingle-line text inputHeadings, button labels
urlSingle-line URL inputLinks, redirect URLs
paragraphMulti-line text inputIntro copy, descriptions
selectDropdown with optionsTheme picker, layout variants
checkboxBoolean toggleShow/hide optional sections
imageImage uploaderHero images, logos

Using fields in HTML with Liquid

Reference a field value: {{ template.fieldSlug }}

Conditionally show content based on a checkbox or optional field:

{% if template.showDisclaimer != blank %}
  <div class="disclaimer">Terms and conditions apply.</div>
{% endif %}

Branch on a select field value:

{% if template.layout == 'wide' %}
  <div class="content-wide">...</div>
{% else %}
  <div class="content-narrow">...</div>
{% endif %}

See the Building page and ballot templates guide for the full HTML/CSS/Liquid reference.

API endpoints

Fetching a template

curl -H "Authorization: Token YOUR_API_TOKEN" \
  "https://app.example.com/api/flow_templates/42"

Returns the full template including body_html, styles_css, head_html, and fields.

Searching templates

curl -H "Authorization: Token YOUR_API_TOKEN" \
  "https://app.example.com/api/flow_templates/search?query=survey"

Creating a template

curl -X POST \
  -H "Authorization: Token YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  "https://app.example.com/api/flow_templates"

Creates a blank template. Use the update endpoint to add content.

Updating a template

This is the main endpoint for setting HTML, CSS, and fields:

curl -X PUT \
  -H "Authorization: Token YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "flow_template": {
      "name": "Branded Survey",
      "styles_css": ".template-body { font-family: Arial; } .header { background: #2c3e50; color: white; padding: 2rem; text-align: center; }",
      "body_html": "<div class=\"header\"><h1>{{ template.heading }}</h1></div><div class=\"content\"><surveyform></surveyform></div>",
      "fields": [
        {
          "slug": "heading",
          "label": "Page Heading",
          "questionType": "text",
          "wysiwyg": true,
          "defaultValue": "Take our survey",
          "translatable": true
        }
      ]
    }
  }' \
  "https://app.example.com/api/flow_templates/42"

Other endpoints are available for cloning, archiving, restoring, and deleting templates — see the API reference for details.