Templates

Versioned HTML email templates with merge tags, variables, fallbacks and a preheader, compatible with Resend templates, used by campaigns, sequences and POST /emails.

A template is HTML with merge tags, plus optional subject, preheader, from and reply_to defaults. You edit a draft; publishing freezes it into an immutable version, and sends always use a published version. Campaigns, sequences and transactional POST /emails can all send from a template.

Create and publish

curl https://api.stamp0.com/templates \
  -H "Authorization: Bearer $STAMP0_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Welcome",
    "alias": "welcome",
    "subject": "Welcome to Acme, {{ contact.first_name | default: \"there\" }}",
    "preheader": "Three things to try first",
    "html": "<p>Hi {{ contact.first_name | default: \"there\" }},</p><p>Your trial ends on {{{TRIAL_END}}}.</p>",
    "variables": [{ "key": "TRIAL_END", "type": "string", "fallback_value": "soon" }]
  }'

curl -X POST https://api.stamp0.com/templates/welcome/publish \
  -H "Authorization: Bearer $STAMP0_API_KEY"
  • Every path takes the tpl_… id or the alias.
  • PATCH changes the draft only; sends keep using the published version until you publish again. Publishing an unchanged draft makes no new version.
  • GET /templates/:id shows has_unpublished_versions when the draft differs; GET /templates/:id/versions lists the published versions.
  • HTML may be up to 1 MiB. Without text, the plain-text part is generated from the HTML; set text: "" to send HTML only.
  • Deleting a template that a scheduled campaign uses answers 409.

React Email. Stamp0 never compiles or runs JSX on its servers. Render your component to HTML and send that as html (the Resend Node SDK does this for react:). A react field is stored as source text for re-editing only.

Merge tags

TagValue
{{ contact.first_name }}, {{ contact.email }}, {{ contact.<property> }}The recipient contact and its properties
{{ company.name }}The contact's company
{{ ORDER_ID }} or {{{ORDER_ID}}}A template variable
{{ unsubscribe_url }}, {{ preferences_url }}The recipient's signed links (marketing sends)
{{ physical_address }}, {{ company_name }}From the project's marketing settings

Filters: default: "…", upcase, downcase, capitalize, strip, truncate: 40, url_encode. Values are always HTML-escaped in the body and forced onto one line in the subject and preheader. Resend's triple-brace syntax works too: {{{FIRST_NAME|there}}}, {{{RESEND_UNSUBSCRIBE_URL}}}.

Variables (up to 50) are typed string or number, with an optional fallback_value. A send must supply every variable the template uses unless it has a fallback or an inline default; otherwise it fails with 422. Variables cannot use reserved names such as contact, email, first_name, unsubscribe_url or RESEND_UNSUBSCRIBE_URL.

Preview and test

  • POST /templates/:id/render returns the subject, preheader, HTML and text exactly as they would be sent, rendered as one of your contacts (contact) or a sample contact. Variables with no value show as [KEY] and are listed in missing. Pass draft: true to render the unpublished draft.
  • POST /templates/:id/test sends one rendered copy to your own verified address. It works from a dashboard or OAuth (MCP) session, not with an API key.

Transactional sends from a template

POST /emails and /emails/batch accept Resend's template field. html and text cannot be combined with it, and from and subject become optional because the template supplies them:

await resend.emails.send({
  to: 'maya@northwind.dev',
  template: { id: 'welcome', variables: { TRIAL_END: 'November 3' } },
});

Transactional sends are not marketing email: they get no unsubscribe headers or footer, and they count toward the plan's email quota, not the marketing one.

Reference: Templates.

On this page