ZapSMTP / Docs / Templates
Update a template
PATCH/v1/templates/{id}
Update a template (partial).
Requires a full-access live key; test keys get 403 test_key_restricted.
Fields left out keep their value; the same validation as create applies to the result.
Every save (and publish) is kept in the version history: see List versions.
has_unpublished_changes is also true when only the draft’s variable_schema differs from the published one.
Path parameters
idstringrequired- Template id or alias
Body parameters
namestring- Limits: trimmed, 1-200 characters → 422 missing_required_field "name is required (max 200 chars)"
aliasstring- Stable handle;
""removes it 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- Mustache source; {{var}} is HTML-escaped, {{{var}}} raw.
textstringfromstring- Default From used when a send omits from.
variablesobject- Sample variables used by previews; replaces the whole object. 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 requiredobject, any other name as a requiredany, never stricter than sends were before, and declared names the source no longer uses are kept withunused: 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;globalis 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 withtemplate_variables_missing. Defaultfalse. 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.nullmakes it a code template. Changinghtmlwithout sendingdesigndrops 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 403test_key_restrictedHTTP 403- test-mode keys can send test email and read, not change the account: use a live key
not_foundHTTP 404- template not found
conflictHTTP 409- a template with this alias already exists
payload_too_largeHTTP 413- request body too large (over 4 MB)
missing_required_fieldHTTP 422invalid_parameterHTTP 422template_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"
curl -X PATCH 'https://zapsmtp.xyz/v1/templates/welcome' \
-H "Authorization: Bearer $ZAP_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"subject": "Welcome aboard, {{first_name}}"
}'const res = await fetch('https://zapsmtp.xyz/v1/templates/welcome', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.ZAP_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"subject": "Welcome aboard, {{first_name}}"
}),
});
// 204 No Content (e.g. a delete) has no body
const data = res.status === 204 ? null : await res.json();
if (!res.ok) throw new Error(`${data.name}: ${data.message}`);
console.log(data);import os
import requests
res = requests.patch(
"https://zapsmtp.xyz/v1/templates/welcome",
headers={"Authorization": f"Bearer {os.environ['ZAP_API_KEY']}"},
json={
"subject": "Welcome aboard, {{first_name}}",
},
timeout=30,
)
res.raise_for_status()
print(res.json() if res.status_code != 204 else "deleted")<?php
$ch = curl_init('https://zapsmtp.xyz/v1/templates/welcome');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('ZAP_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'subject' => 'Welcome aboard, {{first_name}}',
]),
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status >= 400) {
throw new RuntimeException($data['message']);
}
print_r($data);package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
body := strings.NewReader(`{
"subject": "Welcome aboard, {{first_name}}"
}`)
req, err := http.NewRequest(
"PATCH",
"https://zapsmtp.xyz/v1/templates/welcome",
body,
)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("ZAP_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}require 'net/http'
require 'json'
uri = URI('https://zapsmtp.xyz/v1/templates/welcome')
req = Net::HTTP::Patch.new(uri)
req['Authorization'] = "Bearer #{ENV.fetch('ZAP_API_KEY')}"
req['Content-Type'] = 'application/json'
req.body = {
subject: "Welcome aboard, {{first_name}}"
}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, (JSON.parse(res.body) unless res.body.to_s.empty?)import java.net.URI;
import java.net.http.*;
public class ZapRequest {
public static void main(String[] args) throws Exception {
var request = HttpRequest.newBuilder(URI.create("https://zapsmtp.xyz/v1/templates/welcome"))
.header("Authorization", "Bearer " + System.getenv("ZAP_API_KEY"))
.header("Content-Type", "application/json")
.method("PATCH", HttpRequest.BodyPublishers.ofString("""
{
"subject": "Welcome aboard, {{first_name}}"
}"""))
.build();
var response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using System.Text;
using var http = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Patch, "https://zapsmtp.xyz/v1/templates/welcome");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("ZAP_API_KEY"));
request.Content = new StringContent("""
{
"subject": "Welcome aboard, {{first_name}}"
}
""", Encoding.UTF8, "application/json");
var response = await http.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");Set
ZAP_API_KEY in your environment.Response 200.