Before you begin
Check out our general API overview before getting started with specific endpoints.
Use the Templates API to seamlessly create, update, and manage email templates programmatically. Whether you use fully custom HTML, hybrid templates compatible with Klaviyo’s drag-and-drop editor, or native drag-and-drop templates, the Templates API offers flexibility for tailored email experiences.
When calling the Templates API, your authentication key must have the appropriate scopes (
templates:read,templates:write).
Use cases
The Templates API supports the following use cases:
- Get, create, and manage templates.
- Create and update HTML, Hybrid and native drag-and-drop templates.
- Render a template with the given template ID and context.
- Clone a template.
Looking to assign a template to a campaign message or fetch template data for a specific campaign message? Check out our Messages endpoints within the Campaigns API.
Data model
A template has the following:
-
idThe template ID.
-
attributes-
name(required)The name of the template.
-
editor_type(required)The type of editor. Supported values:
CODE— custom HTML templates.USER_DRAGGABLE— hybrid templates edited as HTML in the API but compatible with the drag-and-drop editor.SYSTEM_DRAGGABLE— native drag-and-drop templates backed by a structureddefinitionobject.
-
htmlThe HTML contents of the template. Used for
CODEandUSER_DRAGGABLEtemplates. Not used wheneditor_typeisSYSTEM_DRAGGABLE(usedefinitioninstead). -
textThe plaintext version of the template.
-
definitionStructured drag-and-drop template content (body, styles, and related metadata) for
SYSTEM_DRAGGABLEtemplates. Required when creating aSYSTEM_DRAGGABLEtemplate. On Get Templates, thedefinitionattribute is omitted by default; passadditional-fields[template]=definitionto include it in list responses. Get Template includesdefinitionforSYSTEM_DRAGGABLEtemplates. For the exact JSON shape, refer to the endpoint schemas in the API reference. -
ampThe AMP version of the template. Requires an enabled AMP email to access in-app. Not used when
editor_typeisSYSTEM_DRAGGABLE. -
createdThe timestamp of when the template was last created.
-
updatedThe timestamp of when the metric was last updated.
-
Create a template
When creating a template with the Create Template endpoint, your request payload must include at least a template name and an editor type.
- For
CODEorUSER_DRAGGABLEtemplates, include the appropriate HTML-related fields as described in the API reference. - For
SYSTEM_DRAGGABLEtemplates, include adefinitionto define the template content (body, styles, rows, columns, blocks etc).
Create a HTML template
The example below is a CODE template. It utilizes dynamic variables including first_name, last_name, discount_code, and order_total to tailor the content for each recipient. These variables enable seamless personalization when rendering the template.
{
"data": {
"type": "template",
"attributes": {
"name": "Personalized Discount Email",
"editor_type": "CODE",
"html": "<html>\n <head>\n <meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\" />\n <title>Special Discount for You</title>\n <style>\n body {\n background-color: #f6f6f6;\n font-family: sans-serif;\n margin: 20px;\n }\n .main {\n background: #ffffff;\n border-radius: 3px;\n width: 100%;\n }\n .container {\n margin: 0 auto !important;\n width: 600px;\n }\n .wrapper {\n box-sizing: border-box;\n padding: 15px;\n }\n table {\n width: 100%;\n }\n </style>\n </head>\n <body>\n <div class=\"container\">\n <table class=\"main\">\n <tr>\n <td class=\"wrapper\">\n <p>Hello {{ first_name }} {{ last_name }},</p>\n <p>Thank you for your order of ${{ order_total }}!</p>\n <p>As a thank you, here’s a special discount code just for you: <strong>{{ discount_code }}</strong></p>\n <p>Use it at checkout to enjoy your discount.</p>\n </td>\n </tr>\n <tr>\n <td class=\"wrapper\">{% unsubscribe %}</td>\n </tr>\n </table>\n </div>\n </body>\n</html>"
}
}
}
{
"data": {
"type": "template",
"id": "TuG2Zd",
"attributes": {
"name": "Personalized Discount Email",
"editor_type": "CODE",
"html": "<html>\n<head>\n<meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\"/>\n<title>Special Discount for You</title>\n<style>body {\n background-color: #f6f6f6;\n font-family: sans-serif;\n margin: 20px\n }\n.main {\n background: #fff;\n border-radius: 3px;\n width: 100%\n }\n.container {\n margin: 0 auto !important;\n width: 600px\n }\n.wrapper {\n box-sizing: border-box;\n padding: 15px\n }\ntable {\n width: 100%\n }</style></head>\n<body>\n<div class=\"container\">\n<table class=\"main\">\n<tr>\n<td class=\"wrapper\">\n<p>Hello {{ first_name }} {{ last_name }},</p>\n<p>Thank you for your order of ${{ order_total }}!</p>\n<p>As a thank you, here’s a special discount code just for you: <strong>{{ discount_code }}</strong></p>\n<p>Use it at checkout to enjoy your discount.</p>\n</td>\n</tr>\n<tr>\n<td class=\"wrapper\">{% unsubscribe %}</td>\n</tr>\n</table>\n</div>\n</body>\n</html>",
"text": null,
"amp": null,
"created": "2025-02-05T19:12:51.599729+00:00",
"updated": "2025-02-05T19:12:51.599758+00:00"
},
"links": {
"self": "https://a.klaviyo.com/api/templates/TuG2Zd/"
}
},
"links": {
"self": "https://a.klaviyo.com/api/templates"
}
}
Create a drag-and-drop template
The example below is a SYSTEM_DRAGGABLE template. The definition in the request below matches the definition object in the Get Template response for SYSTEM_DRAGGABLE templates (see Get a drag-and-drop template under Fetch templates).
{
"data": {
"type": "template",
"attributes": {
"name": "Spring welcome (DnD)",
"editor_type": "SYSTEM_DRAGGABLE",
"text": "Hi there, thanks for subscribing.",
"definition": {
"body": {
"properties": {},
"styles": {},
"sections": [
{
"content_type": "section",
"type": "section",
"data": {
"properties": {},
"display_options": {},
"styles": {}
},
"rows": [
{
"data": {
"styles": {
"column_layout": "1-column-full-width"
}
},
"columns": [
{
"data": {},
"blocks": [
{
"content_type": "block",
"type": "text",
"data": {
"content": "<p>Hi {{ person.first_name|default:'there' }}, thanks for subscribing.</p>",
"display_options": {},
"styles": {}
}
}
]
}
]
}
]
}
]
},
"styles": [
{"style_type": "base-styles", "properties": {}, "styles": {}},
{"style_type": "text-styles", "styles": {}},
{"style_type": "link-styles", "styles": {}},
{"style_type": "heading-1-styles", "styles": {}},
{"style_type": "heading-2-styles", "styles": {}},
{"style_type": "heading-3-styles", "styles": {}},
{"style_type": "heading-4-styles", "styles": {}},
{"style_type": "mobile-styles", "properties": {}, "styles": {}}
]
}
}
}
}
{
"data": {
"type": "template",
"id": "V2kMn9",
"attributes": {
"name": "Spring welcome (DnD)",
"editor_type": "SYSTEM_DRAGGABLE",
"html": "<html><head><meta charset=\"utf-8\"/><title>Spring welcome</title></head><body><p>Hi {{ person.first_name|default:'there' }}, thanks for subscribing.</p></body></html>",
"text": "Hi there, thanks for subscribing.",
"definition": {
"body": {
"properties": {},
"styles": {},
"sections": [
{
"content_type": "section",
"type": "section",
"data": {
"properties": {},
"display_options": {},
"styles": {}
},
"rows": [
{
"data": {
"styles": {
"column_layout": "1-column-full-width"
}
},
"columns": [
{
"data": {},
"blocks": [
{
"content_type": "block",
"type": "text",
"data": {
"content": "<p>Hi {{ person.first_name|default:'there' }}, thanks for subscribing.</p>",
"display_options": {},
"styles": {}
}
}
]
}
]
}
]
}
]
},
"styles": [
{"style_type": "base-styles", "properties": {}, "styles": {}},
{"style_type": "text-styles", "styles": {}},
{"style_type": "link-styles", "styles": {}},
{"style_type": "heading-1-styles", "styles": {}},
{"style_type": "heading-2-styles", "styles": {}},
{"style_type": "heading-3-styles", "styles": {}},
{"style_type": "heading-4-styles", "styles": {}},
{"style_type": "mobile-styles", "properties": {}, "styles": {}}
]
},
"amp": null,
"created": "2026-04-10T15:30:00+00:00",
"updated": "2026-04-10T15:30:00+00:00"
},
"links": {
"self": "https://a.klaviyo.com/api/templates/V2kMn9/"
}
},
"links": {
"self": "https://a.klaviyo.com/api/templates"
}
}
Adding universal content to a template
Currently, our APIs do not natively support referencing universal content blocks directly in the payload. You'll need to fetch the block's content (via Get Universal Content), add the content to your template, and upload the final HTML. See our Universal Content API overview for more information on managing universal content blocks via API.
Render a template
Render a template with a given template ID and context attribute (a JSON object with the context the email template is rendered with). A call to Render Template returns the AMP, HTML, and plain text versions of the email template.
Here’s the request and response for rendering the template we created above:
{
"data": {
"type": "template",
"id": "TuG2Zd",
"attributes": {
"context": {
"first_name": "John",
"last_name": "Doe",
"discount_code": "WELCOME10",
"order_total": 49.99
}
}
}
}
{
"data": {
"type": "template",
"id": "TuG2Zd",
"attributes": {
"name": "Personalized Discount Email",
"editor_type": "CODE",
"html": "<html>\n<head>\n<meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\"/>\n<title>Special Discount for You</title>\n<style>body {\n background-color: #f6f6f6;\n font-family: sans-serif;\n margin: 20px\n }\n.main {\n background: #fff;\n border-radius: 3px;\n width: 100%\n }\n.container {\n margin: 0 auto !important;\n width: 600px\n }\n.wrapper {\n box-sizing: border-box;\n padding: 15px\n }\ntable {\n width: 100%\n }</style></head>\n<body>\n<div class=\"container\">\n<table class=\"main\">\n<tr>\n<td class=\"wrapper\">\n<p>Hello John Doe,</p>\n<p>Thank you for your order of $49.99!</p>\n<p>As a thank you, here’s a special discount code just for you: <strong>WELCOME10</strong></p>\n<p>Use it at checkout to enjoy your discount.</p>\n</td>\n</tr>\n<tr>\n<td class=\"wrapper\"><a class=\"unsubscribe-link\" href=\"[unsubscribe_tag]\">Unsubscribe</a></td>\n</tr>\n</table>\n</div>\n</body>\n</html>",
"text": null,
"amp": null,
"created": "2025-02-05T19:12:52+00:00",
"updated": "2025-02-05T19:12:52+00:00"
},
"links": {
"self": "https://a.klaviyo.com/api/templates/TuG2Zd/"
}
},
"links": {
"self": "https://a.klaviyo.com/api/template-render"
}
}
Clone a template
To clone the template we created and rendered above, your request payload for Clone Template should look like the following:
{
"data": {
"type": "template",
"id": "TuG2Zd",
"attributes": {
"name": "Clone of Personalized Discount Email"
}
}
}
{
"data": {
"type": "template",
"id": "XRPRey",
"attributes": {
"name": "Clone of Personalized Discount Email",
"editor_type": "CODE",
"html": "<html>\n<head>\n<meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\"/>\n<title>Special Discount for You</title>\n<style>body {\n background-color: #f6f6f6;\n font-family: sans-serif;\n margin: 20px\n }\n.main {\n background: #fff;\n border-radius: 3px;\n width: 100%\n }\n.container {\n margin: 0 auto !important;\n width: 600px\n }\n.wrapper {\n box-sizing: border-box;\n padding: 15px\n }\ntable {\n width: 100%\n }</style></head>\n<body>\n<div class=\"container\">\n<table class=\"main\">\n<tr>\n<td class=\"wrapper\">\n<p>Hello {{ first_name }} {{ last_name }},</p>\n<p>Thank you for your order of ${{ order_total }}!</p>\n<p>As a thank you, here’s a special discount code just for you: <strong>{{ discount_code }}</strong></p>\n<p>Use it at checkout to enjoy your discount.</p>\n</td>\n</tr>\n<tr>\n<td class=\"wrapper\">{% unsubscribe %}</td>\n</tr>\n</table>\n</div>\n</body>\n</html>",
"text": null,
"amp": null,
"created": "2025-02-05T19:35:59.752156+00:00",
"updated": "2025-02-05T19:35:59.832098+00:00"
},
"links": {
"self": "https://a.klaviyo.com/api/templates/XRPRey/"
}
},
"links": {
"self": "https://a.klaviyo.com/api/template-clone"
}
}
Cloning and creating templates will fail if your account contains 1,000 or more templates, as the Templates API has a limit of 1,000 templates.
Manage templates
Update and delete templates with the Update Template and Delete Template endpoints, respectively.
Fetch templates
All template types are returned when making a Get Template or Get Templates request.
For SYSTEM_DRAGGABLE templates, the structured definition attribute behaves differently by endpoint:
- Get Template includes
definitionin the response for a single template - Get Templates omits
definitionby default
To include definition on each item in a list response, add ?additional-fields[template]=definition to the URL. Learn more in the guide to additional fields. CODE and USER_DRAGGABLE templates do not use definition.
Get an HTML template
curl --request GET \
--url https://a.klaviyo.com/api/templates/U7bDHv \
--header 'Authorization: Klaviyo-API-Key your-private-api-key' \
--header 'accept: application/vnd.api+json' \
--header 'revision: 2026-04-15'
{
"data": {
"type": "template",
"id": "U7bDHv",
"attributes": {
"name": "Clone of Monthly Newsletter Template",
"editor_type": "CODE",
"html": "<html><head></head><body>Template HTML content</body></html>",
"text": null,
"amp": null,
"created": "2025-02-04T20:39:18+00:00",
"updated": "2025-02-04T20:39:18+00:00"
},
"links": {
"self": "https://a.klaviyo.com/api/templates/U7bDHv/"
}
},
"links": {
"self": "https://a.klaviyo.com/api/templates/U7bDHv"
}
}
Get a drag-and-drop template
For SYSTEM_DRAGGABLE templates, the response includes a structured definition and a rendered html preview. The definition object matches the payload in the Create a drag-and-drop template example earlier in this overview (under Create a template).
curl --request GET \
--url https://a.klaviyo.com/api/templates/Qw8tRm \
--header 'Authorization: Klaviyo-API-Key your-private-api-key' \
--header 'accept: application/vnd.api+json' \
--header 'revision: 2026-04-15'
{
"data": {
"type": "template",
"id": "Qw8tRm",
"attributes": {
"name": "Spring welcome (DnD)",
"editor_type": "SYSTEM_DRAGGABLE",
"html": "<html><head><meta charset=\"utf-8\"/><title>Spring welcome</title></head><body><p>Hi {{ person.first_name|default:'there' }}, thanks for subscribing.</p></body></html>",
"text": "Hi there, thanks for subscribing.",
"definition": {
"body": {
"properties": {},
"styles": {},
"sections": [
{
"content_type": "section",
"type": "section",
"data": {
"properties": {},
"display_options": {},
"styles": {}
},
"rows": [
{
"data": {
"styles": {
"column_layout": "1-column-full-width"
}
},
"columns": [
{
"data": {},
"blocks": [
{
"content_type": "block",
"type": "text",
"data": {
"content": "<p>Hi {{ person.first_name|default:'there' }}, thanks for subscribing.</p>",
"display_options": {},
"styles": {}
}
}
]
}
]
}
]
}
]
},
"styles": [
{"style_type": "base-styles", "properties": {}, "styles": {}},
{"style_type": "text-styles", "styles": {}},
{"style_type": "link-styles", "styles": {}},
{"style_type": "heading-1-styles", "styles": {}},
{"style_type": "heading-2-styles", "styles": {}},
{"style_type": "heading-3-styles", "styles": {}},
{"style_type": "heading-4-styles", "styles": {}},
{"style_type": "mobile-styles", "properties": {}, "styles": {}}
]
},
"amp": null,
"created": "2026-04-10T14:22:00+00:00",
"updated": "2026-04-10T14:22:00+00:00"
},
"links": {
"self": "https://a.klaviyo.com/api/templates/Qw8tRm/"
}
},
"links": {
"self": "https://a.klaviyo.com/api/templates/Qw8tRm"
}
}
Querying templates
Querying templates with the Templates API can help you achieve many use cases, such as sorting templates by the date they were created. Check out the supported query parameters below and test them with our latest Postman collection. Note that support for given operators and fields is endpoint-specific. Review the API reference documentation for more information on allowed fields and query operators.
| Parameter | Description | Query example |
|---|---|---|
filter | Retrieve a subset of templates, e.g., templates that have been created within a given time frame. Learn about the filter query parameter. | GET /api/templates?filter=greater-than(created,"2023-06-05T12:30:00+00:00") |
sort | Sort templates, e.g., by date created in ascending order (oldest to newest). Learn about the sort query parameter. | GET /api/templates?sort=created |
fields | Request for only specified template data, e.g., name. Learn more about sparse fieldsets. | GET /api/templates?fields[template]=name |
additional-fields[template] | Include the definition attribute for each template in Get Templates responses (needed for SYSTEM_DRAGGABLE templates). Learn more about additional fields. | GET /api/templates?additional-fields[template]=definition |