Runs examples for real against your account. Test keys only; kept in this tab, never stored on our side. Get a key
ZapSMTP / Docs / Templates

Create a template

POST/v1/templates

Create a template (logic-less Mustache).

Requires a full-access live key; test keys get 403 test_key_restricted.

Syntax: {{var}} escaped, {{{var}}} raw, {{#list}}…{{/list}} sections, {{^x}}…{{/x}} inverted sections. Exact ordering of variable_names is determined by the parser; the example order is illustrative.

Body: html and text both empty → 422 missing_required_field; template syntax errors → 422 template_render_error "<field>: <error>"; a tag that is not a variable name ({{first name}}, {{#each items}}, {{> footer}}) → 422 template_render_error "html: line L, column C: {{…}} is not a variable name: …"

variable_schema in the response is the saved list after discovery. A send is checked against the published copy, published.variable_schema.

Body parameters

namestringrequired
Limits: trimmed, 1-200 characters → 422 missing_required_field "name is required (max 200 chars)"
aliasstring
Stable handle usable instead of the id (template.id in sends, /templates/{alias}). Limits: ^[a-z0-9][a-z0-9_-]{0,62}$ → 422 invalid_parameter; duplicate → 409 conflict
subjectstring
Mustache source.
htmlstring
At least one of html and text is required. Mustache source; {{var}} is HTML-escaped, {{{var}}} raw.
textstring
fromstring
Default From used when a send omits from.
variablesobject
Sample variables used by previews. Never used for sending; a variable first found in the source takes its sample as example.
variable_schemaobject[]
Declares the template’s variables (see Variable schema). Replaces the declared list when given. On every save, names the source uses that the list lacks are added (their sample value as example): a section {{#x}} as optional any, a dotted {{x.y}} as a required object, any other name as a required any, never stricter than sends were before, and declared names the source no longer uses are kept with unused: true. Limits: at most 200 entries, no duplicates, defaults and examples of their type → 422 invalid_parameter "variable_schema: <reason>"
Show 6 fields
namestringrequired
Variable name: letters, digits, _ and -, starting with a letter or _, up to 64; global is reserved.
typestringrequired
What a send must pass. One of string, number, boolean, url, date, list, object, any.
requiredboolean
A send without a value (or with null) and without a default is refused with template_variables_missing. Default false.
defaultany
Used when a send gives no value; must be of type.
exampleany
Used by previews; must be of type.
descriptionstring
For your team; at most 500 bytes.
designobject | null
The visual editor’s document (a JSON object with a numeric version), stored with the template. null makes it a code template. Changing html without sending design drops the design (it no longer describes the HTML). Limits: max 1 MB → 422 invalid_parameter "design is larger than 1 MB"; not an object with a numeric version → 422 invalid_parameter
publishboolean
Publish the result in the same call. Without it the template stays a draft and is not used for sending until published. Default false.

Errors

restricted_api_keyHTTP 403
test_key_restrictedHTTP 403
test-mode keys can send test email and read, not change the account: use a live key
conflictHTTP 409
a template with this alias already exists
payload_too_largeHTTP 413
request body too large (over 4 MB)
missing_required_fieldHTTP 422
invalid_parameterHTTP 422
template_render_errorHTTP 422
template syntax error: "<field>: <error>"
template_render_errorHTTP 422
a tag that is not a variable name, e.g. {{first name}}, {{#each items}}, {{> footer}}: "html: line L, column C: {{…}} is not a variable name: letters, digits, _ and - (no spaces), parts joined with dots"
POST/v1/templates
curl -X POST 'https://zapsmtp.xyz/v1/templates' \
  -H "Authorization: Bearer $ZAP_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Welcome",
  "alias": "welcome",
  "subject": "Welcome, {{first_name}}",
  "html": "<p>Hi {{first_name}}, your workspace is ready.</p>",
  "publish": true
}'
Set ZAP_API_KEY in your environment.
Response 201 Created
{
  "id": "019a1f23-7f80-7192-8b3c-4d5e6f7a8b9c",
  "name": "Receipt",
  "alias": "receipt",
  "subject": "Your receipt for {{order_id}}",
  "html": "<p>Hi {{name}}, thanks for order {{order_id}}.</p>",
  "text": "Hi {{name}}, thanks for order {{order_id}}.",
  "from": "Acme <billing@acme.com>",
  "variables": {
    "name": "Jane",
    "order_id": "A-1042"
  },
  "variable_schema": [
    {
      "name": "order_id",
      "type": "string",
      "required": true,
      "example": "A-1042",
      "description": "Order number shown to the customer"
    },
    {
      "name": "name",
      "type": "string",
      "required": false,
      "default": "there",
      "example": "Jane"
    }
  ],
  "design": null,
  "created_at": "2026-10-21T16:10:00Z",
  "updated_at": "2026-10-21T16:10:00Z",
  "object": "template",
  "variable_names": [
    "order_id",
    "name"
  ],
  "status": "draft",
  "has_unpublished_changes": false,
  "published_at": null,
  "published": null
}