A new draft, holding version 1 of its content.
Body
Body| Field | Type | Description |
|---|
name* | string | A name for the dashboard. |
alias | string | A short name to address the template by instead of its ID: lower-case letters, digits, - and _, starting with a letter or digit, at most 63 characters, and never a UUID. Unique among the team's templates. |
from | string | The sender, as Name <address@domain> or a bare address. A send that names its own from overrides it. |
subject | string | The subject line. May carry {{key}} placeholders. |
html* | string | The HTML body. May carry {{key}} placeholders. |
text | string | The plain-text body. May carry {{key}} placeholders. |
variables | object[] | The variables the bodies use, at most 200: { key, type, fallback_value }, with type one of string, number, boolean, object or list. Every {{key}} must be declared here, and every declared key must be used. |
›1 more field (reply_to)
Body, less common| Field | Type | Description |
|---|
reply_to | string[] | Reply-to addresses. |
curl -X POST "https://api.rasket.com/templates" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-d '{
"name": "Welcome",
"alias": "welcome",
"subject": "Welcome, {{name}}",
"html": "<p>Hello {{name}}, thanks for joining.</p>",
"variables": [
{
"key": "name",
"type": "string",
"fallback_value": "there"
}
]
}'
const response = await fetch("https://api.rasket.com/templates", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Welcome",
alias: "welcome",
subject: "Welcome, {{name}}",
html: "<p>Hello {{name}}, thanks for joining.</p>",
variables: [
{
key: "name",
type: "string",
fallback_value: "there"
}
]
}),
});
const { id } = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/templates",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
json={
"name": "Welcome",
"alias": "welcome",
"subject": "Welcome, {{name}}",
"html": "<p>Hello {{name}}, thanks for joining.</p>",
"variables": [
{
"key": "name",
"type": "string",
"fallback_value": "there"
}
]
},
)
id = response.json()["id"]
Response 201
{
"id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
"object": "template"
}
- A new template is a draft. Nothing can be sent from it until you publish it.
- A
{{key}} the bodies use but variables does not declare — or a declared key the bodies never use — is 422 validation_error, with one entry in errors[] per key. - An alias another live template holds is
422 validation_error. Deleting a template frees its alias.
Every template, most recently changed first.
Query parameters
Query parameters| Field | Type | Description |
|---|
limit | integer | How many items to return, 1–100. Defaults to 20. |
after | string | Return the page that follows this item ID. Mutually exclusive with before. |
before | string | Return the page that precedes this item ID. Mutually exclusive with after. |
curl -X GET "https://api.rasket.com/templates?limit=20" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/templates?limit=20", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const data = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/templates?limit=20",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
print(response.json())
Response 200
{
"object": "list",
"has_more": false,
"data": [
{
"id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
"name": "Welcome",
"status": "published",
"published_at": "2026-09-11T12:00:00.000Z",
"created_at": "2026-09-11T12:00:00.000Z",
"updated_at": "2026-09-11T12:00:00.000Z",
"alias": "welcome"
}
]
}
- Items carry no content. Retrieve one template for its bodies and variables.
alias is present only on templates that have one.
By ID or by alias, with the current version's content.
Path parameters
Path parameters| Field | Type | Description |
|---|
id* | string | The template's ID or its alias. An alias is matched case-insensitively. |
curl -X GET "https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const { id } = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
id = response.json()["id"]
Response 200
{
"object": "template",
"id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
"current_version_id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d18",
"name": "Welcome",
"alias": "welcome",
"from": "Acme <hello@acme.com>",
"subject": "Welcome, {{name}}",
"reply_to": null,
"html": "<p>Hello {{name}}, thanks for joining.</p>",
"text": "Hello {{name}}, thanks for joining.",
"variables": [
{
"id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d19",
"key": "name",
"type": "string",
"fallback_value": "there",
"created_at": "2026-09-11T12:00:00.000Z",
"updated_at": "2026-09-11T12:00:00.000Z"
}
],
"created_at": "2026-09-11T12:00:00.000Z",
"updated_at": "2026-09-11T12:00:00.000Z",
"status": "published",
"published_at": "2026-09-11T12:00:00.000Z",
"has_unpublished_versions": false
}
- The content shown is the **current** version — the open draft, if there is one.
has_unpublished_versions: true means it differs from what sends use. alias, from, subject and text are absent, not null, when unset.- A template that belongs to another team, or that has been deleted, is
404 not_found.
Write the draft. Sends keep using the published version.
Path parameters
Path parameters| Field | Type | Description |
|---|
id* | string | The template's ID or its alias. An alias is matched case-insensitively. |
Body
Body| Field | Type | Description |
|---|
name | string | A new name. |
alias | string | null | A new alias, or null to remove the current one. |
from | string | null | The sender, as Name <address@domain> or a bare address. A send that names its own from overrides it. null clears it. |
subject | string | null | The subject line. May carry {{key}} placeholders. null clears it. |
html | string | The HTML body. May carry {{key}} placeholders. |
text | string | The plain-text body. May carry {{key}} placeholders. |
variables | object[] | The variables the bodies use, at most 200: { key, type, fallback_value }, with type one of string, number, boolean, object or list. Every {{key}} must be declared here, and every declared key must be used. |
›1 more field (reply_to)
Body, less common| Field | Type | Description |
|---|
reply_to | string[] | Reply-to addresses. |
curl -X PATCH "https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-d '{
"subject": "Welcome aboard, {{name}}"
}'
const response = await fetch("https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
},
body: JSON.stringify({
subject: "Welcome aboard, {{name}}"
}),
});
const { id } = await response.json();
import os
import requests
response = requests.patch(
"https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
json={
"subject": "Welcome aboard, {{name}}"
},
)
id = response.json()["id"]
Response 200
{
"id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
"object": "template"
}
- On a published template with no open draft, the first update starts a new version; later updates edit that draft in place. Publish it when it is ready.
- Only the fields you send change. The declaration rule applies to the merged result: the bodies after your change must still declare and use exactly the same keys as
variables. - An empty body is
422 invalid_parameter.
Remove it and free its alias.
Path parameters
Path parameters| Field | Type | Description |
|---|
id* | string | The template's ID or its alias. An alias is matched case-insensitively. |
curl -X DELETE "https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const { id } = await response.json();
import os
import requests
response = requests.delete(
"https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
id = response.json()["id"]
Response 200
{
"object": "template",
"id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
"deleted": true
}
- The template answers
404 not_found from this moment, and a send that names it is 422 invalid_parameter. - Emails already sent from it keep their record of which version they used.
Make the current version the one sends use.
Path parameters
Path parameters| Field | Type | Description |
|---|
id* | string | The template's ID or its alias. An alias is matched case-insensitively. |
curl -X POST "https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17/publish" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17/publish", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const { id } = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17/publish",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
id = response.json()["id"]
Response 200
{
"id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
"object": "template"
}
- Publishing takes effect for the next send. Emails already queued keep the version they resolved.
- Publishing a template whose current version is already published changes nothing and still answers
200.
A new draft holding a copy of the current version.
Path parameters
Path parameters| Field | Type | Description |
|---|
id* | string | The template's ID or its alias. An alias is matched case-insensitively. |
curl -X POST "https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17/duplicate" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17/duplicate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const { id } = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17/duplicate",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
id = response.json()["id"]
Response 200
{
"id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d2a",
"object": "template"
}
- The copy is named
<name> (copy), has no alias, and is a draft. The source is untouched. - What is copied is the current version — the open draft, if there is one — not the published one.
Render a version with values filled in, the way a send would. Nothing is stored.
Path parameters
Path parameters| Field | Type | Description |
|---|
id* | string | The template's ID or its alias. An alias is matched case-insensitively. |
Body
Body| Field | Type | Description |
|---|
variables | object | Values by key, strings or numbers, as a send takes them. An undeclared key or a value of the wrong type is 422 invalid_parameter. |
version | integer | The version number to render. The current version when absent. |
curl -X POST "https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17/preview" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-d '{
"variables": {
"name": "Ronald"
}
}'
const response = await fetch("https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17/preview", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
},
body: JSON.stringify({
variables: {
name: "Ronald"
}
}),
});
const data = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/templates/0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17/preview",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
json={
"variables": {
"name": "Ronald"
}
},
)
print(response.json())
Response 200
{
"object": "template_preview",
"template_id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5d17",
"version_number": 1,
"subject": "Welcome, Ronald",
"html": "<p>Hello Ronald, thanks for joining.</p>",
"text": "Hello Ronald, thanks for joining.",
"missing_variables": []
}
- A declared variable with neither a value nor a fallback is listed in
missing_variables, and its placeholder is left in place. html has been sanitised, with remote images withheld. Show it in a sandboxed iframe, never straight in a page.