Templates
Saved email templates plus the premade base templates — create them, fetch them, and send from them with a templateId.
Auth: Session token · Base URL:
https://api.mailkite.dev
Endpoints
Each row expands to its request and response schema. The address bar follows along, so any endpoint can be linked to directly.
GET /api/templates List your saved email templates (light metadata only — no body). Use getTemplate for the full template.
List your saved email templates (light metadata only — no body). Use getTemplate for the full template.
The light shape list endpoints return — identity and labelling only. The html/json/text/theme blobs are omitted here because a gallery never renders them; fetch one template by id to get the full row.
| Field | Type | Notes |
|---|---|---|
| id req | string | Template id. User templates are tpl_…; base (premade) templates are base_<slug>. Either can be passed as send()'s templateId. |
| name req | string | Display name, as shown in the template gallery. |
| category req | string | Gallery group for base templates (Welcome, Receipt, …). Empty string for user templates, which are not grouped. |
| subject req | string | Default subject line applied when sending with this template. Empty string when the template does not set one. |
| is_base req | 0 · 1 | 1 for a premade base template (world-readable, owned by the system), 0 for one of your own. Base templates cannot be edited — clone one via createTemplate's baseId. |
| updated_at req | integer | When the template was last modified, in Unix epoch milliseconds (UTC). List endpoints sort by this, newest first. |
An actual array of results, recorded from the conformance suite.
[
{
"id": "tpl_2Hk9QpVn4tLd",
"name": "Welcome email",
"category": "",
"subject": "Welcome to MailKite",
"is_base": 0,
"updated_at": 1769731200000
}
] {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/template-meta.json",
"title": "Template (list row)",
"description": "The light shape list endpoints return — identity and labelling only. The html/json/text/theme blobs are omitted here because a gallery never renders them; fetch one template by id to get the full row.",
"type": "object",
"required": [
"id",
"name",
"category",
"subject",
"is_base",
"updated_at"
],
"properties": {
"id": {
"type": "string",
"description": "Template id. User templates are tpl_…; base (premade) templates are base_<slug>. Either can be passed as send()'s templateId.",
"examples": [
"tpl_2Hk9QpVn4tLd"
]
},
"name": {
"type": "string",
"description": "Display name, as shown in the template gallery.",
"examples": [
"Welcome email"
]
},
"category": {
"type": "string",
"description": "Gallery group for base templates (Welcome, Receipt, …). Empty string for user templates, which are not grouped.",
"examples": [
"Welcome"
]
},
"subject": {
"type": "string",
"description": "Default subject line applied when sending with this template. Empty string when the template does not set one.",
"examples": [
"Welcome to MailKite"
]
},
"is_base": {
"type": "integer",
"enum": [
0,
1
],
"description": "1 for a premade base template (world-readable, owned by the system), 0 for one of your own. Base templates cannot be edited — clone one via createTemplate's baseId.",
"examples": [
0
]
},
"updated_at": {
"type": "integer",
"description": "When the template was last modified, in Unix epoch milliseconds (UTC). List endpoints sort by this, newest first.",
"examples": [
1769731200000
]
}
}
} GET /api/templates/base List the premade base templates (light metadata). Clone one with createTemplate({ baseId }) or send from it directly via send({ templateId }).
List the premade base templates (light metadata). Clone one with createTemplate({ baseId }) or send from it directly via send({ templateId }).
The light shape list endpoints return — identity and labelling only. The html/json/text/theme blobs are omitted here because a gallery never renders them; fetch one template by id to get the full row.
| Field | Type | Notes |
|---|---|---|
| id req | string | Template id. User templates are tpl_…; base (premade) templates are base_<slug>. Either can be passed as send()'s templateId. |
| name req | string | Display name, as shown in the template gallery. |
| category req | string | Gallery group for base templates (Welcome, Receipt, …). Empty string for user templates, which are not grouped. |
| subject req | string | Default subject line applied when sending with this template. Empty string when the template does not set one. |
| is_base req | 0 · 1 | 1 for a premade base template (world-readable, owned by the system), 0 for one of your own. Base templates cannot be edited — clone one via createTemplate's baseId. |
| updated_at req | integer | When the template was last modified, in Unix epoch milliseconds (UTC). List endpoints sort by this, newest first. |
An actual array of results, recorded from the conformance suite.
[
{
"id": "base_welcome",
"name": "Welcome",
"category": "Welcome",
"subject": "Welcome to MailKite",
"is_base": 1,
"updated_at": 1769731200000
}
] {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/template-meta.json",
"title": "Template (list row)",
"description": "The light shape list endpoints return — identity and labelling only. The html/json/text/theme blobs are omitted here because a gallery never renders them; fetch one template by id to get the full row.",
"type": "object",
"required": [
"id",
"name",
"category",
"subject",
"is_base",
"updated_at"
],
"properties": {
"id": {
"type": "string",
"description": "Template id. User templates are tpl_…; base (premade) templates are base_<slug>. Either can be passed as send()'s templateId.",
"examples": [
"tpl_2Hk9QpVn4tLd"
]
},
"name": {
"type": "string",
"description": "Display name, as shown in the template gallery.",
"examples": [
"Welcome email"
]
},
"category": {
"type": "string",
"description": "Gallery group for base templates (Welcome, Receipt, …). Empty string for user templates, which are not grouped.",
"examples": [
"Welcome"
]
},
"subject": {
"type": "string",
"description": "Default subject line applied when sending with this template. Empty string when the template does not set one.",
"examples": [
"Welcome to MailKite"
]
},
"is_base": {
"type": "integer",
"enum": [
0,
1
],
"description": "1 for a premade base template (world-readable, owned by the system), 0 for one of your own. Base templates cannot be edited — clone one via createTemplate's baseId.",
"examples": [
0
]
},
"updated_at": {
"type": "integer",
"description": "When the template was last modified, in Unix epoch milliseconds (UTC). List endpoints sort by this, newest first.",
"examples": [
1769731200000
]
}
}
} GET /api/templates/:id Get one template (full: subject, html, text, theme). Works for your templates (tpl_…) and base templates (base_…).
Get one template (full: subject, html, text, theme). Works for your templates (tpl_…) and base templates (base_…).
Response body
template.jsonA saved email template, returned in full by getTemplate and createTemplate. Pass its id as send()'s templateId to use it: the stored subject/html/text seed the message, and anything you pass to send() explicitly overrides them.
| Field | Type | Notes |
|---|---|---|
| id req | string | Template id. User templates are tpl_…; base (premade) templates are base_<slug>. |
| user_id req | string | Owner of the template. The literal string "system" for base templates, which belong to no account. |
| name req | string | Display name, as shown in the template gallery. |
| category req | string | Gallery group for base templates (Welcome, Receipt, …). Empty string for user templates. |
| subject req | string | Default subject line applied when sending with this template. Empty string when the template does not set one. |
| json req | string | The editor document as a JSON string (TipTap format). This is the re-editable source the dashboard's template editor loads; `html` is what actually gets sent. Defaults to "{}". |
| html req | string | The rendered, inbox-safe HTML body used when sending. Empty string for a template that has no HTML part. |
| text req | string | Plain-text fallback body used when sending. Empty string for a template that has no text part. |
| theme req | string | Brand tokens as a JSON string (bg, surface, primary, text, logo, …) applied when the editor re-renders the HTML. Defaults to "{}". |
| is_base req | 0 · 1 | 1 for a premade base template (world-readable, owned by the system), 0 for one of your own. Base templates cannot be edited — clone one via createTemplate's baseId. |
| created_at req | integer | When the template was created, in Unix epoch milliseconds (UTC). |
| updated_at req | integer | When the template was last modified, in Unix epoch milliseconds (UTC). |
An actual response, recorded from the conformance suite.
{
"id": "tpl_2Hk9QpVn4tLd",
"user_id": "usr_7Fj3MnQw",
"name": "Welcome email",
"category": "",
"subject": "Welcome to MailKite",
"json": "{\"type\":\"doc\",\"content\":[]}",
"html": "<h1>Welcome, {{name}}</h1>",
"text": "Welcome, {{name}}",
"theme": "{\"primary\":\"#3b82f6\"}",
"is_base": 0,
"created_at": 1769731200000,
"updated_at": 1769731200000
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/template.json",
"title": "Template",
"description": "A saved email template, returned in full by getTemplate and createTemplate. Pass its id as send()'s templateId to use it: the stored subject/html/text seed the message, and anything you pass to send() explicitly overrides them.",
"type": "object",
"required": [
"id",
"user_id",
"name",
"category",
"subject",
"json",
"html",
"text",
"theme",
"is_base",
"created_at",
"updated_at"
],
"properties": {
"id": {
"type": "string",
"description": "Template id. User templates are tpl_…; base (premade) templates are base_<slug>.",
"examples": [
"tpl_2Hk9QpVn4tLd"
]
},
"user_id": {
"type": "string",
"description": "Owner of the template. The literal string \"system\" for base templates, which belong to no account.",
"examples": [
"usr_7Fj3MnQw"
]
},
"name": {
"type": "string",
"description": "Display name, as shown in the template gallery.",
"examples": [
"Welcome email"
]
},
"category": {
"type": "string",
"description": "Gallery group for base templates (Welcome, Receipt, …). Empty string for user templates.",
"examples": [
""
]
},
"subject": {
"type": "string",
"description": "Default subject line applied when sending with this template. Empty string when the template does not set one.",
"examples": [
"Welcome to MailKite"
]
},
"json": {
"type": "string",
"description": "The editor document as a JSON string (TipTap format). This is the re-editable source the dashboard's template editor loads; `html` is what actually gets sent. Defaults to \"{}\".",
"examples": [
"{\"type\":\"doc\",\"content\":[]}"
]
},
"html": {
"type": "string",
"description": "The rendered, inbox-safe HTML body used when sending. Empty string for a template that has no HTML part.",
"examples": [
"<h1>Welcome, {{name}}</h1>"
]
},
"text": {
"type": "string",
"description": "Plain-text fallback body used when sending. Empty string for a template that has no text part.",
"examples": [
"Welcome, {{name}}"
]
},
"theme": {
"type": "string",
"description": "Brand tokens as a JSON string (bg, surface, primary, text, logo, …) applied when the editor re-renders the HTML. Defaults to \"{}\".",
"examples": [
"{\"primary\":\"#3b82f6\"}"
]
},
"is_base": {
"type": "integer",
"enum": [
0,
1
],
"description": "1 for a premade base template (world-readable, owned by the system), 0 for one of your own. Base templates cannot be edited — clone one via createTemplate's baseId.",
"examples": [
0
]
},
"created_at": {
"type": "integer",
"description": "When the template was created, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
},
"updated_at": {
"type": "integer",
"description": "When the template was last modified, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
}
}
} POST /api/templates Create a template. Pass `baseId` to clone a base template into your own, or provide name/subject/html/text/theme directly.
Create a template. Pass `baseId` to clone a base template into your own, or provide name/subject/html/text/theme directly.
Request body
create-template-request.json| Field | Type | Notes |
|---|---|---|
| baseId | string | Clone this base template (base_…) into your own. When set, name is optional (defaults to the base's name). |
| name | string | Template name. Required unless baseId is given. |
| subject | string | Default subject line for sends. |
| html | string | Rendered, send-ready HTML. |
| text | string | Plaintext fallback. |
| json | string | Editor (TipTap) JSON source, for re-editing in the dashboard. |
| theme | string | Brand tokens JSON (bg, surface, primary, text, logo, …). |
The smallest body that makes this call — every other field is optional.
{
"baseId": "base_welcome",
"name": "My Welcome"
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/create-template-request.json",
"title": "Create template request body",
"type": "object",
"additionalProperties": false,
"properties": {
"baseId": {
"type": "string",
"description": "Clone this base template (base_…) into your own. When set, name is optional (defaults to the base's name)."
},
"name": {
"type": "string",
"description": "Template name. Required unless baseId is given."
},
"subject": {
"type": "string",
"description": "Default subject line for sends."
},
"html": {
"type": "string",
"description": "Rendered, send-ready HTML."
},
"text": {
"type": "string",
"description": "Plaintext fallback."
},
"json": {
"type": "string",
"description": "Editor (TipTap) JSON source, for re-editing in the dashboard."
},
"theme": {
"type": "string",
"description": "Brand tokens JSON (bg, surface, primary, text, logo, …)."
}
}
} Response body
template.jsonA saved email template, returned in full by getTemplate and createTemplate. Pass its id as send()'s templateId to use it: the stored subject/html/text seed the message, and anything you pass to send() explicitly overrides them.
| Field | Type | Notes |
|---|---|---|
| id req | string | Template id. User templates are tpl_…; base (premade) templates are base_<slug>. |
| user_id req | string | Owner of the template. The literal string "system" for base templates, which belong to no account. |
| name req | string | Display name, as shown in the template gallery. |
| category req | string | Gallery group for base templates (Welcome, Receipt, …). Empty string for user templates. |
| subject req | string | Default subject line applied when sending with this template. Empty string when the template does not set one. |
| json req | string | The editor document as a JSON string (TipTap format). This is the re-editable source the dashboard's template editor loads; `html` is what actually gets sent. Defaults to "{}". |
| html req | string | The rendered, inbox-safe HTML body used when sending. Empty string for a template that has no HTML part. |
| text req | string | Plain-text fallback body used when sending. Empty string for a template that has no text part. |
| theme req | string | Brand tokens as a JSON string (bg, surface, primary, text, logo, …) applied when the editor re-renders the HTML. Defaults to "{}". |
| is_base req | 0 · 1 | 1 for a premade base template (world-readable, owned by the system), 0 for one of your own. Base templates cannot be edited — clone one via createTemplate's baseId. |
| created_at req | integer | When the template was created, in Unix epoch milliseconds (UTC). |
| updated_at req | integer | When the template was last modified, in Unix epoch milliseconds (UTC). |
An actual response, recorded from the conformance suite.
{
"id": "tpl_9Wm4RtYu2Bnc",
"user_id": "usr_7Fj3MnQw",
"name": "My Welcome",
"category": "",
"subject": "",
"json": "{}",
"html": "",
"text": "",
"theme": "{}",
"is_base": 0,
"created_at": 1769731200000,
"updated_at": 1769731200000
} {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.mailkite.dev/v1/schemas/template.json",
"title": "Template",
"description": "A saved email template, returned in full by getTemplate and createTemplate. Pass its id as send()'s templateId to use it: the stored subject/html/text seed the message, and anything you pass to send() explicitly overrides them.",
"type": "object",
"required": [
"id",
"user_id",
"name",
"category",
"subject",
"json",
"html",
"text",
"theme",
"is_base",
"created_at",
"updated_at"
],
"properties": {
"id": {
"type": "string",
"description": "Template id. User templates are tpl_…; base (premade) templates are base_<slug>.",
"examples": [
"tpl_2Hk9QpVn4tLd"
]
},
"user_id": {
"type": "string",
"description": "Owner of the template. The literal string \"system\" for base templates, which belong to no account.",
"examples": [
"usr_7Fj3MnQw"
]
},
"name": {
"type": "string",
"description": "Display name, as shown in the template gallery.",
"examples": [
"Welcome email"
]
},
"category": {
"type": "string",
"description": "Gallery group for base templates (Welcome, Receipt, …). Empty string for user templates.",
"examples": [
""
]
},
"subject": {
"type": "string",
"description": "Default subject line applied when sending with this template. Empty string when the template does not set one.",
"examples": [
"Welcome to MailKite"
]
},
"json": {
"type": "string",
"description": "The editor document as a JSON string (TipTap format). This is the re-editable source the dashboard's template editor loads; `html` is what actually gets sent. Defaults to \"{}\".",
"examples": [
"{\"type\":\"doc\",\"content\":[]}"
]
},
"html": {
"type": "string",
"description": "The rendered, inbox-safe HTML body used when sending. Empty string for a template that has no HTML part.",
"examples": [
"<h1>Welcome, {{name}}</h1>"
]
},
"text": {
"type": "string",
"description": "Plain-text fallback body used when sending. Empty string for a template that has no text part.",
"examples": [
"Welcome, {{name}}"
]
},
"theme": {
"type": "string",
"description": "Brand tokens as a JSON string (bg, surface, primary, text, logo, …) applied when the editor re-renders the HTML. Defaults to \"{}\".",
"examples": [
"{\"primary\":\"#3b82f6\"}"
]
},
"is_base": {
"type": "integer",
"enum": [
0,
1
],
"description": "1 for a premade base template (world-readable, owned by the system), 0 for one of your own. Base templates cannot be edited — clone one via createTemplate's baseId.",
"examples": [
0
]
},
"created_at": {
"type": "integer",
"description": "When the template was created, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
},
"updated_at": {
"type": "integer",
"description": "When the template was last modified, in Unix epoch milliseconds (UTC).",
"examples": [
1769731200000
]
}
}
}