Templates

A template is a subject and a body with holes in it. You store it once, and each send fills the holes:

curl -X POST https://api.avelto.dev/v1/emails \
  -H "Authorization: Bearer av_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": "[email protected]",
    "template_slug": "welcome",
    "variables": {
      "name": "Ada",
      "plan": "Growth"
    }
  }'

No subject, no html, no text — the template owns those. Passing one alongside a template is an error rather than an override, because two places deciding what a message says is a support question waiting to happen. The reverse holds too: variables without a template is refused.

The template language, in full

There isn't one. The entire grammar is a name between braces:

FormWhat it does
{{name}}The value, HTML-escaped in the HTML part
{{{name}}}The value exactly as given

A name is letters, digits and underscores, not starting with a digit; {{ name }} with spaces is fine. Anything else between braces is left as written. String values may be up to 10,000 characters.

No loops, no conditionals, no partials, no property access, no expressions, no filters. That is a deliberate ceiling rather than a roadmap: every one of those turns your template into a program that runs on our servers, and the history of template engines is a history of that program escaping.

If you need a list of order lines, build the HTML for it yourself and pass it as one variable with {{{lines}}}. You keep the loop, in your own language, where you can test it.

Escaping

{{name}} is escaped in the HTML part and left alone in the subject and the plain text part, so the same variable is safe in both. A customer called Ada <[email protected]> renders as text, not as a broken tag.

{{{name}}} skips the escaping. Use it when you are passing markup you built, and not when you are passing something a user typed.

Missing variables are an error

A template that refers to {{name}} and a send that does not pass one is refused with 422, listing every variable that was missing:

JSON
{
  "error": {
    "code": "validation_error",
    "message": "The template needs values for these variables: company, name. Pass them in variables.",
    "details": { "missing_variables": ["company", "name"] }
  }
}

Not an empty string. "Hi ," sent to a hundred thousand people is worse in every way than a send that did not happen, and the error names all of them at once so it is one fix rather than a guessing game.

Values

Strings, numbers, booleans and null. null renders as nothing, which is what an absent middle name should do. Objects and arrays are refused — see the ceiling above.

Managing templates

POST /v1/templates with a name, a subject, and html, text or both. The slug is derived from the name unless you set one, and it is what you pass as template_slug. Slugs are lower-case letters, digits and hyphens (welcome-email). A derived slug that is already taken gets a numeric suffix; a slug you set yourself must be free or the request is 409 conflict. On a send, name the template with template_slug or template_id, not both. An unknown slug or id is 404 not_found.

TypeScript
import { Avelto } from "@avelto/sdk";
const avelto = new Avelto(process.env.AVELTO_API_KEY);

const template = await avelto.templates.create({
  name: "Welcome",
  subject: "Welcome, {{name}}",
  html: "<p>Hello {{name}}</p>",
});

await avelto.emails.send({
  from: "[email protected]",
  to: "[email protected]",
  template_slug: template.slug,
  variables: { name: "Ada" },
});

GET, PATCH and DELETE /v1/templates/{id} do what you expect. A key needs the templates:manage scope for any of them.

Versions

Every save adds a version; version 1 is the template as you first created it, and version on the template is the current one. GET /v1/templates/{id}/versions lists them, and POST /v1/templates/{id}/restore with a version puts one back.

Restoring writes the old version forward as a new one rather than rewinding, so the history is append-only and a restore is itself something you can undo. The mistake you restored away from is still there.

What a send keeps

The rendered subject and body are copied onto the email when it is accepted. Editing a template afterwards does not change what was already sent, and deleting one does not orphan it — the email log still shows exactly what went out.

In the dashboard

Templates has an editor with the same preview the email log uses, a panel listing the variables it found in your body, and a button that sends the template to the account owner's address in test mode so you can look at it in a real mail client.