Templates

Create reusable email templates with {{variable}} placeholders, then send with POST /emails using template: { id, variables }.

Base URL: https://api.ranla.ai


Authentication

Authorization: Bearer rnl_…

Requires a full-scope API key (or dashboard session). Sending-scoped keys cannot manage templates.


Model

Field Notes
name Required; unique per account
alias Optional unique handle (not empty, not starting with rnl_ or stx_)
status draft (default) or published
format html (legacy) or blocks (visual builder document)
subject / html / text Support {{var}} placeholders
preheader Optional inbox preview text
design TemplateDocument JSON when format is blocks
variables Variable names (auto-extracted for blocks templates)
published_version_id Immutable version used for sends
unsubscribe_enabled When true, sends using this template inherit managed unsubscribe unless overridden per send
category transactional (default), product, or newsletter. Product and newsletter support category-scoped opt-out
warnings Non-blocking deliverability hints for html (e.g. SVG logos)

Placeholders in HTML bodies are HTML-escaped when interpolated. Subject and text are not.

Publishing snapshots an immutable version. Sends always resolve published_version_id, so draft edits never break live aliases. See docs/templates/builder.md.

Global CSS (blocks templates)

design.settings.globalCss accepts ordinary CSS that is compiled for the inbox on render:

  • Rules whose selector is a bare tag (body, p, h1, h2, h3, a, img, hr) become inline styles on those elements and override per-block styling. Inlining matters because Gmail drops <style> on clipped and forwarded messages, and Outlook renders through Word.
  • Everything else — class and id selectors, pseudo-classes, descendant selectors, media queries — is emitted into a <style> block, which most clients honour.
{
  "design": {
    "version": 1,
    "settings": {
      "globalCss": "p { color: rgb(63,63,70); }\n@media (max-width: 480px) { p { font-size: 14px; } }"
    }
  }
}

@import is stripped, and CSS cannot inject markup.

Images in HTML

Use PNG or JPG logos at public https:// URLs in <img src="…"> tags. Many inboxes (including Gmail) do not render SVG images. Ranla returns advisory warnings on template create/get/list when HTML may not render reliably — sends are not blocked.

<img src="https://yourdomain.com/assets/logo.png" alt="Your product" width="36" height="36" />

List

GET /templates

Query: limit, cursor, optional status=draft|published.

{
  "data": [
    {
      "id": "…",
      "name": "Welcome",
      "alias": "welcome",
      "status": "published",
      "subject": "Hello {{name}}",
      "html": "<p>Hi {{name}}</p>",
      "text": "Hi {{name}}",
      "variables": ["name"],
      "published_at": "2026-07-26T12:00:00.000Z",
      "created_at": "2026-07-26T11:00:00.000Z",
      "updated_at": "2026-07-26T12:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Create

POST /templates201

{
  "name": "Welcome",
  "alias": "welcome",
  "subject": "Hello {{name}}",
  "html": "<p>Hi {{name}}</p>",
  "text": "Hi {{name}}",
  "variables": ["name"]
}

Creates a draft. Publish before sending.


Starter catalog

GET /templates/starters — list copyable starters (full-scope key).

POST /templates/from-starter — copy one into your account as published with a fixed alias.

Alias Variables
password-reset name, reset_url
email-verification name, verify_url, code
welcome name, dashboard_url
invoice name, amount, invoice_url, invoice_id
team-invite name, inviter_name, team_name, invite_url
curl -X POST https://api.ranla.ai/templates/from-starter \
  -H "Authorization: Bearer $RANLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"alias":"password-reset"}'
await client.templates.fromStarter('password-reset')
await client.emails.send({
  from: '[email protected]',
  to: '[email protected]',
  template: {
    id: 'password-reset',
    variables: { name: 'Ada', reset_url: 'https://app.example.com/reset?token=…' },
  },
})

Dashboard: Templates → Start from a template. Returns 409 if the name or alias already exists on the account.


Retrieve / update / delete

  • GET /templates/{id} — UUID or alias
  • PATCH /templates/{id} — update fields
  • DELETE /templates/{id}

Publish / duplicate

POST /templates/{id}

{ "action": "publish" }
{ "action": "duplicate", "name": "Welcome (copy)" }

Duplicate creates a new draft (alias cleared). name is optional (defaults to … (copy)).


Send with a template

POST /emails

{
  "from": "[email protected]",
  "to": "[email protected]",
  "template": {
    "id": "welcome",
    "variables": { "name": "Ada" }
  }
}

template is mutually exclusive with html / text. Subject comes from the template unless you pass subject to override. Only published templates can be used.


SDK

import { Ranla } from '@supersend/ranla'

const client = new Ranla(process.env.RANLA_API_KEY!)

const { template } = await client.templates.create({
  name: 'Welcome',
  alias: 'welcome',
  subject: 'Hello {{name}}',
  html: '<p>Hi {{name}}</p>',
})
await client.templates.publish(template.id)

await client.emails.send({
  from: '[email protected]',
  to: '[email protected]',
  template: { id: 'welcome', variables: { name: 'Ada' } },
})

React Email (optional peer)

Install @react-email/render (and react) to pass a React element:

npm install @react-email/render react
await client.emails.send({
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Hello',
  react: EmailComponent({ name: 'Ada' }),
})

The SDK compiles react to HTML before POST /emails. Mutually exclusive with html / text / template.

Full guide: Send React Email.


CLI

supersendtx templates list
supersendtx templates starters
supersendtx templates from-starter password-reset
supersendtx templates create --name Welcome --subject "Hi {{name}}" --html "<p>Hi {{name}}</p>" --alias welcome --category product --unsubscribe-enabled
supersendtx templates update --id welcome --category product --unsubscribe-enabled

Push from your repo

templates push upserts a template from a local file, keyed by --alias, so your repo can be the source of truth:

# HTML file
supersendtx templates push ./emails/welcome.html --alias welcome --subject "Welcome" --publish

# React Email component, rendered locally
supersendtx templates push ./emails/WelcomeEmail.tsx --alias welcome --props '{"name":"Ada"}' --publish
Flag Notes
<file> .html, .txt, or a module (.js, .mjs, .cjs, .jsx, .ts, .tsx) with a React component as its default export
--alias Required. Creates the template on first push, updates it afterwards
--subject Required only when creating
--name Display name; defaults to the alias
--preheader Inbox preview text
--text <file> Attach a hand-written plain-text part
--props <json> Props passed to the component when rendering
--publish Cut a published version after pushing

Module files are imported in your process and rendered with @react-email/render — only the resulting HTML and text are uploaded. TypeScript and JSX need a loader: install tsx (npm install -D tsx) or pre-render to .html. See React Email guide.


OpenAPI

openapi/supersendtx.yaml