Getting Started
Templates
Pre-approved message content with declared variables. Optional for email; required for SMS and WhatsApp.
A template is pre-approved message content with declared
variables. You reference it by id (tpl_…) when you send; we
render the body against the variables you pass.
Templates aren’t required for every channel:
| Channel | Templates | Why |
|---|---|---|
| Optional | You can also send a raw HTML or text body directly. | |
| SMS | Required | Carrier networks require pre-registered content for transactional traffic. |
| Required | WhatsApp’s network only delivers approved templates outside the 24h window. |
When you do use a template, you get three things that direct sends can’t offer:
- Editable copy. Your support team can tweak wording in the dashboard without a code deploy.
- Server-injected brand. Variables like
{{brand.name}}and{{brand.support_email}}are filled in from your verified domain at send time. A leaked API key can’t impersonate another brand on your team. - Variable validation. Required keys, type checks, and missing-variable errors run before the message is dispatched.
What’s in a template
Each template has:
- A name for humans (e.g. “Order confirmation”).
- A channel —
email,sms, orwhatsapp. - A content body with
{{handlebars}}placeholders. - A variable manifest — the declared list of variables the template accepts, with type and required/optional metadata.
When you call POST /v1/{channel}, we validate the variables
you pass against the manifest and reject mismatches before the
send leaves the API.
Authoring templates
Templates are authored in the dashboard under Templates → New template. Pick the channel, write the body, and declare variables as you go. The dashboard previews the rendered output side-by-side using sample values.
For email, the body is HTML with a plain-text fallback. For SMS, the body is plain text capped at 1600 characters once rendered. For WhatsApp, the body matches a pre-registered template body on the WhatsApp network — only the variable values you pass travel over the wire; the body itself is rendered by the provider from the pre-registered version.
Variable manifest
Each declared variable has:
| Field | Meaning |
|---|---|
key | The placeholder name, used as {{customer.key}}. |
label | A human label shown in the dashboard preview. |
required | When true, omitting it returns 422 missing_variable. |
type | One of string, number, email, phone, url, code. |
The order of variables matters for WhatsApp: it’s the order
of the positional placeholders ({{1}}, {{2}}, …) in the
pre-registered template body. The dashboard makes the ordering
visible so you can’t get it wrong.
Send-time substitution
Variables you send live in the customer.* namespace and the
brand fields live in brand.*. So a template body like:
Hi {{customer.first_name}}, your {{brand.name}} verification
code is {{customer.code}}. Reply STOP to opt out.
For help, email {{brand.support_email}}.
With this request:
{
"to": "+2348012345678",
"template_id": "tpl_…",
"variables": {
"first_name": "Ada",
"code": "847291"
}
}
Renders as:
Hi Ada, your Acme verification code is 847291.
Reply STOP to opt out. For help, email support@acme.com.
You never pass brand.* values from your code — they’re filled
in from your domain’s brand profile on the server side.
Re-using templates across teams
Templates are scoped to your team. If you have a staging team and a production team, author the templates in each one (you can copy-paste). Keeping them separate means a draft template can’t accidentally go live before you mean it to.
Updated at, Thursday, October 1, 2026