OpenAPI Spec
Machine-readable spec for the Templates API: stable/categories/templates.json
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.
- Convert an HTML template into a drag-and-drop 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.
Convert an HTML template to drag-and-drop
Convert a CODE template into a new SYSTEM_DRAGGABLE template with Create Template Conversion Job. The conversion runs asynchronously, so the request returns a job instead of the new template. The source template does not change. The new template is named after the source template, followed by (converted).
Starting a conversion requires an account on a paid plan. Requests from other accounts return a 403 error. Any account can still get and list its conversion jobs.
Only CODE templates can be converted. If the source template is a different editor type, the request returns a 400 error. If the source template does not exist, the request returns a 404 error.
Creating a conversion job requires the
templates:writescope and is limited to 1 request/second burst and 1 request/minute steady. Reading conversion jobs requires thetemplates:readscope.
Start a conversion
To convert the HTML template we created above, set it as the source-template relationship:
{
"data": {
"type": "template-conversion-job",
"relationships": {
"source-template": {
"data": {
"type": "template",
"id": "TuG2Zd"
}
}
}
}
}
{
"data": {
"type": "template-conversion-job",
"id": "XyZ123-01JA8ZQ5M0V3T7N6K2H4B9C1DE",
"attributes": {
"status": "queued",
"created_at": "2026-10-15T14:00:00+00:00",
"error": null,
"completed_at": null
},
"relationships": {
"source-template": {
"data": {
"type": "template",
"id": "TuG2Zd"
}
}
},
"links": {
"self": "https://a.klaviyo.com/api/template-conversion-jobs/XyZ123-01JA8ZQ5M0V3T7N6K2H4B9C1DE/"
}
},
"links": {
"self": "https://a.klaviyo.com/api/template-conversion-jobs/"
}
}
Check the job status
Poll Get Template Conversion Job until the job's status is complete or failed. A job has one of these statuses:
queued— the job is waiting to start.processing— the conversion is running.complete— the new template exists. Its ID is in theconverted-templaterelationship.failed— the conversion did not finish. Theerrorattribute says why.
The converted-template relationship is only included when the status is complete.
curl --request GET \
--url https://a.klaviyo.com/api/template-conversion-jobs/XyZ123-01JA8ZQ5M0V3T7N6K2H4B9C1DE \
--header 'Authorization: Klaviyo-API-Key your-private-api-key' \
--header 'accept: application/vnd.api+json' \
--header 'revision: 2026-10-15'
{
"data": {
"type": "template-conversion-job",
"id": "XyZ123-01JA8ZQ5M0V3T7N6K2H4B9C1DE",
"attributes": {
"status": "complete",
"created_at": "2026-10-15T14:00:00+00:00",
"error": null,
"completed_at": "2026-10-15T14:03:00+00:00"
},
"relationships": {
"source-template": {
"data": {
"type": "template",
"id": "TuG2Zd"
}
},
"converted-template": {
"data": {
"type": "template",
"id": "Rw4pLk"
}
}
},
"links": {
"self": "https://a.klaviyo.com/api/template-conversion-jobs/XyZ123-01JA8ZQ5M0V3T7N6K2H4B9C1DE/"
}
},
"links": {
"self": "https://a.klaviyo.com/api/template-conversion-jobs/XyZ123-01JA8ZQ5M0V3T7N6K2H4B9C1DE/"
}
}
Get the new template with Get Template, using the ID from the converted-template relationship.
List conversion jobs
Get Template Conversion Jobs returns the conversion jobs created in the last 7 days, newest first. This endpoint does not support filtering or pagination.
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 |