Templates
Reusable content for campaigns, transactional sends and automations.
| GET/POST | /api/v1/templates | Elenca o crea un template di contenuto riusabile (e' cosi' che si ottiene un templateId valido).(scope: templates:read|write) |
| GET/PATCH | /api/v1/templates/:id | Dettaglio col contenuto, oppure modifica parziale (i campi assenti restano).(scope: templates:read|write) |
| DELETE | /api/v1/templates/:id | Elimina un template: 409 se una campagna lo usa ancora.(scope: templates:write) |
A template is reusable content stored in your workspace. Every send path accepts a templateId
instead of inline content: POST /api/v1/emails, POST /api/v1/messages, campaigns, and the
message nodes of an automation. This is the endpoint that gives you a valid one.
POST /api/v1/templates
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | 2 to 200 chars. Unique per workspace. |
body | string | yes | The content. With format: "blocks" it is the JSON of an EmailDoc. |
channels | array | no | Any of email, whatsapp, telegram. Defaults to ["email"]. |
format | string | no | Email: markdown, html (default) or blocks. Chat channels are always text. |
subject | string | yes for email | Rejected with subject_required when the template covers email. |
channelText | object | no | Per-channel text for whatsapp / telegram. Without it the base body is degraded to plain text. |
const { template } = await sending.templates.create({
name: "Welcome",
subject: "Welcome aboard, {{firstName}}",
format: "html",
body: "<p>Hi {{firstName}}, glad you are here.</p>",
});
await sending.emails.send({
from: "Acme <[email protected]>",
to: "[email protected]",
templateId: template.id,
idempotencyKey: "welcome-sara-001",
});The variables array in the response is derived from the content: the {{...}} placeholders are
read from subject, body and per-channel overrides, so you never declare them. A placeholder that
matches no contact field comes back in warnings, and is not an error: at send time it renders
empty (or falls back to {{key|default:...}}).
Names are unique
A duplicate name answers 409 template_exists and includes the templateId that already
exists. It does not attach to it the way tags and lists do: those are records, where the natural
key is the thing, while a template is content, and handing back the id of different content
would send a campaign with the wrong body. Reuse the id you get back, or fix it with PATCH.
GET /api/v1/templates
Returns up to 200 templates, most recently updated first, without their body. Add ?channel=email
to keep only the ones usable on a channel, ?limit= to page down.
GET /api/v1/templates/{id}
The full template, body included. Read it before correcting it, and to see which variables it expects before using it in a send.
PATCH /api/v1/templates/{id}
Partial update: only the fields you pass change. The rules stay coupled to each other, so changing
just the body of a blocks template still requires a valid EmailDoc, and removing the subject of
an email template is rejected.
Campaigns that already went out do not change: they carry the content frozen at send time.
curl -X PATCH "https://sending.dev/api/v1/templates/<id>" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "subject": "Welcome aboard!" }'DELETE /api/v1/templates/{id}
Rejected with 409 template_in_use while a campaign still references the template; the
response lists the campaigns, so you know what to fix first.
Errors
| Code | Status | Meaning |
|---|---|---|
template_exists | 409 | A template with that name exists. The response carries its templateId. |
template_in_use | 409 | A campaign still references it. The response lists them. |
subject_required | 422 | The template covers email and has no subject. |
invalid_format | 422 | Email templates accept markdown, html or blocks only. |
invalid_document | 422 | format: "blocks" and the body is not a valid EmailDoc. |
no_channels | 422 | No valid channel left after normalization. |
MCP
The same surface is available to agents as list_templates, get_template, create_template and
update_template, under the templates:read and templates:write scopes.