Templates
Versioned templates with variables, referenced by `templateKey` (`publiq.templates`).
The templates resource covers a versioned template lifecycle: create (with html/subject/text and variables), fetch, list, preview a saved version and, for the AI builder, render or save from a json-render SPEC.
Method reference
templates.create
templates.create(params) → Promise<Template>Creates a versioned template from HTML (with interpolated variables). Automatically generates a readable key and the template's first version.
| Parameter | Type | Description |
|---|---|---|
nameRequired | string | Template name. Must be unique within the organization. |
htmlRequired | string | Template HTML body. May contain {{ variables }} interpolated on send or preview. |
subjectOptional | string | Default subject for the template. May also contain variables. |
textOptional | string | Plain-text alternative to html (fallback and better deliverability). |
engineOptional | string | Render engine for the variables (e.g. handlebars). If omitted, uses the organization default. |
Returns: The created template — includes the auto-generated key and its first version.
const template = await publiq.templates.create({
name: 'welcome-email',
subject: 'Welcome, {{ first_name }}!',
html: '<h1>Hi {{ first_name }}</h1><p>Welcome to {{ company }}.</p>',
text: 'Hi {{ first_name }}, welcome to {{ company }}.',
});
console.log(template.id, template.key); // "tpl_...", "welcome-email"key (readable slug, e.g. welcome-email) can be used in Emails (emails.send({ templateKey })) and in Broadcasts (broadcasts.create({ templateId })). Variables use {{ snake_case }} — see Variables.templates.get
templates.get(id) → Promise<Template>Fetch a template details by id, including versions[] and the readable key.
| Parameter | Type | Description |
|---|---|---|
idRequired | string | Template ID (returned by templates.create). |
Returns: The template with its version history (versions[]) and key. 404 if it does not exist in the organization.
const template = await publiq.templates.get('tpl_123');
console.log(template.key, template.versions.length);key returned here is the same one accepted by emails.send({ templateKey }) and broadcasts.create({ templateId }) — see Emails and Broadcasts.templates.list
templates.list({ limit?, after? }) → Promise<TemplateList>List the organization templates, newest first, cursor-paginated. Each item is a summary with version_count.
| Parameter | Type | Description |
|---|---|---|
limitOptional | number | Items per page (default 20, max 100). |
afterOptional | string | Cursor: id of the last item on the previous page. |
Returns: List envelope { object: "list", data: TemplateSummary[] }. Use the last item id as after on the next call.
const { data } = await publiq.templates.list({ limit: 50 });
// next page:
const next = await publiq.templates.list({ after: data[data.length - 1].id });id in after until data comes back empty. See Errors & pagination.templates.preview
templates.preview(id, { version? }) → Promise<TemplatePreview>Renders a saved template version with its variables resolved, for visual review before sending.
| Parameter | Type | Description |
|---|---|---|
idRequired | string | Template ID. |
versionOptional | string | Version to preview. If omitted, uses the latest version. |
Returns: A preview { object: "template_preview", subject, html } with the subject and HTML already rendered.
const preview = await publiq.templates.preview('tpl_123', { version: '2' });
console.log(preview.subject, preview.html);templates.render
templates.render(params) → Promise<TemplateRender>Renders a json-render SPEC ({ root, elements, state }) on the fly, without persisting anything — this is the live preview used by the AI builder.
| Parameter | Type | Description |
|---|---|---|
specRequired | object | A json-render SPEC — { root, elements, state } — describing the email element tree. |
Returns: { object: "template_render", html, text } — rendered result, not saved.
const spec = {
root: 'body',
elements: {
body: { type: 'container', children: ['heading'] },
heading: { type: 'text', content: 'Hi {{ first_name }}' },
},
state: {},
};
const rendered = await publiq.templates.render({ spec });
console.log(rendered.html);render and fromSpec power the AI builder and require the ai_builder plan feature. render is a non-persisting preview; use templates.fromSpec to save the result as a new template version.templates.fromSpec
templates.fromSpec(params) → Promise<Template>Renders a json-render SPEC and saves the result as a new template (or new version), with an auto-generated key.
| Parameter | Type | Description |
|---|---|---|
nameRequired | string | Template name. Must be unique within the organization. |
specRequired | object | A json-render SPEC — { root, elements, state } — the same structure used in templates.render. |
subjectOptional | string | Template subject. |
Returns: The template created from the rendered SPEC, with an auto-generated key.
const template = await publiq.templates.fromSpec({
name: 'newsletter-july',
subject: 'Your July newsletter',
spec,
});
console.log(template.key);fromSpec (Python: from_spec) requires the ai_builder plan feature, same as render. Unlike render, here the result is saved as a template.Examples show Node, Python and PHP. In Python methods are snake_case (e.g. cancel_run, from_spec) and take a dict; in PHP they are camelCase and take an associative array. Body keys are always camelCase (templateKey, firstName, scheduledAt) — API responses come back in snake_case.