Skip to content
On this site

Templates

Reusable email content with typed variables. Write it once, publish it, and send it by ID or alias with the values filled in.

Versions

A template is a name, an optional alias, and a series of versions of its content — from, subject, reply_to, html, text and the variables they use. Creating a template writes version 1 as a draft. publish makes the current version the one sends use; updating a published template opens the next draft without changing what is sent, until you publish again.

  • Retrieving a template shows the current version. When that is an open draft, has_unpublished_versions is true.
  • A send records the exact version it used, so a later edit never changes what an already-sent email said.
  • Only a published template can be sent. Naming a draft in POST /emails is 422 invalid_parameter.

Variables and placeholders

A placeholder is {{key}} — or {{ key }} — with the key matching ^[A-Za-z0-9_]+$. There is no logic, no filter and no nesting: a value that contains {{other}} is inserted as that literal text, never expanded. Every placeholder the bodies use must be declared in variables, and every declared variable must be used, so an editor can point at exactly what is wrong.

Sends supply values as strings or numbers. A value is checked against the declared type; a key the send omits takes the variable's fallback_value, and a declared key with neither is 422 missing_required_field.

How each variable type renders
TypeRendered as
stringInserted as written: HTML-escaped in html, raw in subject and text.
numberWritten out as a number.
booleantrue or false.
objectCompact JSON, HTML-escaped in html.
listCompact JSON, HTML-escaped in html.

Addressing a template

  • Every {id} below accepts the template's UUID or its alias. An alias is lower-case, may not be a UUID, and is unique among the team's live templates.
  • Reading and listing work with either kind of key. Creating, updating, publishing, duplicating and deleting need a full_access key; a sending_access key gets 401 restricted_api_key.
  • A template in another team is 404 not_found, indistinguishable from one that does not exist.

Endpoints

POST /templates

A new draft, holding version 1 of its content.

Body

Body
FieldTypeDescription
name*stringA name for the dashboard.
aliasstringA 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.
fromstringThe sender, as Name <address@domain> or a bare address. A send that names its own from overrides it.
subjectstringThe subject line. May carry {{key}} placeholders.
html*stringThe HTML body. May carry {{key}} placeholders.
textstringThe plain-text body. May carry {{key}} placeholders.
variablesobject[]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
FieldTypeDescription
reply_tostring[]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"
    }
  ]
}'

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.

GET /templates

Every template, most recently changed first.

Query parameters

Query parameters
FieldTypeDescription
limitintegerHow many items to return, 1–100. Defaults to 20.
afterstringReturn the page that follows this item ID. Mutually exclusive with before.
beforestringReturn 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"

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.

GET /templates/{id}

By ID or by alias, with the current version's content.

Path parameters

Path parameters
FieldTypeDescription
id*stringThe 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"

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.

PATCH /templates/{id}

Write the draft. Sends keep using the published version.

Path parameters

Path parameters
FieldTypeDescription
id*stringThe template's ID or its alias. An alias is matched case-insensitively.

Body

Body
FieldTypeDescription
namestringA new name.
aliasstring | nullA new alias, or null to remove the current one.
fromstring | nullThe sender, as Name <address@domain> or a bare address. A send that names its own from overrides it. null clears it.
subjectstring | nullThe subject line. May carry {{key}} placeholders. null clears it.
htmlstringThe HTML body. May carry {{key}} placeholders.
textstringThe plain-text body. May carry {{key}} placeholders.
variablesobject[]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
FieldTypeDescription
reply_tostring[]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}}"
}'

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.

DELETE /templates/{id}

Remove it and free its alias.

Path parameters

Path parameters
FieldTypeDescription
id*stringThe 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"

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.

POST /templates/{id}/publish

Make the current version the one sends use.

Path parameters

Path parameters
FieldTypeDescription
id*stringThe 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"

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.

POST /templates/{id}/duplicate

A new draft holding a copy of the current version.

Path parameters

Path parameters
FieldTypeDescription
id*stringThe 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"

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.

POST /templates/{id}/preview

Render a version with values filled in, the way a send would. Nothing is stored.

Path parameters

Path parameters
FieldTypeDescription
id*stringThe template's ID or its alias. An alias is matched case-insensitively.

Body

Body
FieldTypeDescription
variablesobjectValues by key, strings or numbers, as a send takes them. An undeclared key or a value of the wrong type is 422 invalid_parameter.
versionintegerThe 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"
  }
}'

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.