Templates

Enable producers to save reusable content (e.g. a poll question with options, an alert's text/image) so they can be reused later when creating a live widget, without retyping the same content.

Overview

A template stores metadata like category, subcategory, name, plus a template_object which holds the actual content like a particular widget object.

Today category only has one valid value: "widgets", but will be extended in future to streaks, quests, leaderboards etc. subcategory identifies the specific widget kind (see Supported widget types).

Base URL

/api/<version>/templates/

Authentication & permissions

Standard application API authentication is required.

  • Read (GET): allowed for any authenticated request.
  • Write (POST, PUT, PATCH, DELETE): requires producer-level permission on the application.

Endpoints

MethodPathDescription
GET/templates/List templates. Supports filtering (see below). template_object is omitted from each item in list responses.
POST/templates/Create a new template.
GET/templates/{id}/Retrieve a single template, including its full template_object.
PUT / PATCH/templates/{id}/Update a template's name and/or template_object. category and subcategory are immutable after creation.
DELETE/templates/{id}/Delete the template.

List filters (query params)

ParamDescription
categoryFilter by category (currently only widgets).
subcategoryFilter by widget type, e.g. text-poll.
is_defaultFilter to default templates (true) or user-created ones (false).

Request / Response envelope

FieldTypeRead/WriteNotes
idUUIDread-only
client_idstringread-onlyIdentifies the owning application.
categorystringwrite-onceRequired on create. Only "widgets" is currently a valid choice.
subcategorystringwrite-onceRequired on create. Must be one of the supported widget types.
namestringread/writeRequired. Must be unique within category.
is_defaultbooleanread-onlytrue for built-in default templates.
using_geniebooleanread-onlytrue if the template was generated using an AI prompt ("Genie").
created_on / updated_ondatetimeread-only
created_by / updated_byobject ({id, name, image_url})read-only
template_objectobjectread/writeRequired on create. Shape depends on subcategory. Omitted from list responses.

Notes

  • Name uniqueness is enforced per category, not per subcategory — two templates in widgets can't share a name even if they're different widget types.
  • Creating a template with an unsupported/unknown subcategory returns 400 with "Unsupported subcategory: <value>.".

Fields common to every widget type

Every template_object, regardless of subcategory, accepts/returns these keys in addition to its widget-specific fields:

FieldTypeRead/WriteRequiredNotes
localized_dataobjectread/writeoptional (default {})Per-locale overrides, keyed by language code, e.g. {"es": {"question": "..."}}.
timeoutstring (ISO-8601 duration)read/writeoptional (default "PT30S")e.g. "PT30S" = 30 seconds.
sponsor_idsarray of UUID stringswrite-onlyoptionalSponsors to attach.
sponsorsarray of objects ({id, url, logo_url, client_id})read-onlyResolved sponsor details, returned in responses.
widget_attributesarray of {"key": string, "value": string}read/writeoptionalArbitrary key/value metadata attached to the widget.

The per-widget tables below list these alongside each widget's own fields.


Supported widget types

subcategory → widget field reference.

alert

FieldTypeRequired
titlestring (≤500 chars)optional
textstring (≤500 chars)optional
image_urlstring (URL, ≤500 chars)optional
link_urlstring (URL, ≤500 chars)optional
link_labelstring (≤200 chars)optional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

video-alert

FieldTypeRequired
titlestring (≤200 chars)optional
textstringoptional
video_urlstring (URL, ≤500 chars)required
link_urlstring (URL, ≤500 chars)optional
link_labelstring (≤200 chars)optional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

text-ask

FieldTypeRequired
titlestringrequired
promptstringrequired
confirmation_messagestringoptional (has a default confirmation message)
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

rich-post

FieldTypeRequired
titlestring (≤200 chars)optional
contentstring (HTML)optional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

text-poll

FieldTypeRequired
questionstringrequired
optionsarray of option objectsoptional
options[].descriptionstringrequired
options[].localized_dataobjectoptional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

image-poll

FieldTypeRequired
questionstringrequired
optionsarray of option objectsoptional
options[].descriptionstringrequired
options[].image_urlstring (URL, ≤500 chars)required
options[].localized_dataobjectoptional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

text-quiz

FieldTypeRequired
questionstringrequired
choicesarray of choice objects (note: key is choices, not options)optional
choices[].descriptionstringrequired
choices[].is_correctbooleanoptional (default false)
choices[].localized_dataobjectoptional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

image-quiz

FieldTypeRequired
questionstringrequired
choicesarray of choice objectsoptional
choices[].descriptionstringrequired
choices[].image_urlstring (URL, ≤500 chars)required
choices[].is_correctbooleanoptional (default false)
choices[].localized_dataobjectoptional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

text-prediction

FieldTypeRequired
questionstringrequired
confirmation_messagestringoptional (has a default confirmation message)
optionsarray of option objectsoptional
options[].descriptionstringrequired
options[].is_correctbooleanoptional (default false)
options[].localized_dataobjectoptional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

image-prediction

FieldTypeRequired
questionstringrequired
confirmation_messagestringoptional (has a default confirmation message)
optionsarray of option objectsoptional
options[].descriptionstringrequired
options[].image_urlstring (URL, ≤500 chars)required
options[].is_correctbooleanoptional (default false)
options[].localized_dataobjectoptional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

image-number-prediction

FieldTypeRequired
questionstringrequired
confirmation_messagestringoptional (has a default confirmation message)
optionsarray of option objectsoptional
options[].descriptionstringrequired
options[].image_urlstring (URL, ≤500 chars)required
options[].correct_numberinteger, nullableoptional
options[].localized_dataobjectoptional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

cheer-meter

FieldTypeRequired
questionstringrequired
optionsarray of option objectsoptional
options[].descriptionstringrequired
options[].image_urlstring (URL, ≤500 chars)required
options[].localized_dataobjectoptional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

emoji-slider

FieldTypeRequired
questionstringrequired
optionsarray of option objectsoptional
options[].image_urlstring (URL, ≤500 chars)required (no description field on this widget's options)
options[].localized_dataobjectoptional
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

social-embed

FieldTypeRequired
commentstringoptional
itemsarray of item objects (key is items)optional
items[].urlstring (URL, ≤500 chars)required
localized_dataobjectoptional
timeoutstring (ISO-8601 duration)optional
sponsor_idsarray of UUIDsoptional
sponsorsarray of objectsread-only
widget_attributesarray of {key, value}optional

Related: using a template to create a live widget

Templates are consumed on the individual widget-creation endpoints (e.g. POST /text-polls/), not on the template-bank endpoint itself. Widget endpoints that support this accept two extra, write-only fields:

FieldTypeNotes
using_template_idUUIDID of a template. Applies that template's content as defaults; any fields also present in the request body override the template's values.
save_widget_as_templatebooleanIf true, saves the widget being created back into the Template Bank as a new template.