Appearance
Create a template
Create a reusable email body you can later publish and send by id. See the Templates guide for the concept and the dashboard editor.
http
POST /v1/templatesRequires a Full access API key — templates are account content, not sending, so a sending key embedded in an app cannot create them.
A template is addressable by its id or its alias (the slug) everywhere a {id} appears in these endpoints. This one returns the id you'll use.
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | A human name for the template. Max 120 characters. |
html | string | Yes | The HTML body. Every {{{tag}}} in it becomes a variable. |
alias | string | No | The slug you can address the template by instead of its id. Auto-derived from name if omitted, and deduplicated within your team (a colliding slug gains a -2, -3, … suffix). Max 64 characters. |
from | string | No | A default sender — email@domain or Name <email@domain>. Used at send unless the send payload overrides it. Max 320 characters. |
subject | string | No | A default subject line. Rendered with the same variables. Max 998 characters. |
reply_to | string | No | A default Reply-To address, overridable at send. Max 320 characters. |
text | string | No | A plain-text body. If omitted, plain text is derived from the HTML at send. |
variables | array | No | Per-variable flags — which are required, and their fallbacks. See Variables. |
Example
bash
curl -X POST 'https://api.sendgrail.com/v1/templates' \
-H "Authorization: Bearer $SENDGRAIL_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"name": "Welcome email",
"alias": "welcome-email",
"from": "Acme <hello@example.com>",
"subject": "Welcome, {{{first_name}}}",
"html": "<p>Hi {{{first_name}}}, your total is {{{price}}}.</p>",
"variables": [
{ "key": "first_name", "required": true },
{ "key": "price", "fallback_value": "25" }
]
}'js
const res = await fetch('https://api.sendgrail.com/v1/templates', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SENDGRAIL_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Welcome email',
alias: 'welcome-email',
from: 'Acme <hello@example.com>',
subject: 'Welcome, {{{first_name}}}',
html: '<p>Hi {{{first_name}}}, your total is {{{price}}}.</p>',
variables: [
{ key: 'first_name', required: true },
{ key: 'price', fallback_value: '25' },
],
}),
});
const template = await res.json();Response
201 Created. Just the id — fetch the full object with Get a template when you want it.
json
{
"object": "template",
"id": "d3f8c2a1-6b47-4e9a-b25c-1f0e7a9d4c83"
}A new template starts as a draft. It cannot be sent until you publish it — a send call referencing a draft is rejected.
Variables
Variables are discovered from the body, not declared. Every unique {{{tag}}} you write in the subject or the html/text becomes a variable automatically — you never list them to bring them into being.
The variables array only sets, per variable, two things:
| Field | Type | Description |
|---|---|---|
key | string | The tag name, without the braces — e.g. price for {{{price}}}. |
required | boolean | Whether the value must be supplied at send. Defaults to false. |
fallback_value | string | The default rendered when the caller omits the value at send. Providing one makes the variable optional. |
How they combine:
- A variable with a
fallback_valueis optional, and renders that default when omitted. Givepriceafallback_valueof"25"and a send that omits it rendersTotal: 25. - A variable with no fallback and
required: truemust be supplied at send, or the send is rejected with422. - A variable that is neither required nor given a fallback renders empty when omitted.
Naming a key that isn't in the body does nothing — only tags actually present become variables. And you don't have to list every tag: any you leave out are still discovered, just with required: false and no fallback.
Different from Resend
Resend declares each variable up front with a type (string or number). SendGrail discovers variables from the body instead and does not track a type — a variable here carries only its key, whether it's required, and an optional fallback_value.
Errors
A Sending access key gets 403 — creating templates needs Full access. See Errors.