Skip to main content

Email templates

The letters your team sends from a record with Send email — see Email templates & snippets in the manual. A template is a subject and a message under a name; a snippet is a paragraph under a name, inserted where the cursor is. Both may carry merge fields such as {{contact.firstName}} and {{deal.amount}}, which the send fills in from the record; the API stores them as written and fills in nothing.

Scopes and the site rule are shared with every CRM resource — see companies.

The email template object

{
"id": "et_7b2f",
"object": "email_template",
"name": "Follow-up",
"kind": "template",
"visibility": "shared",
"ownerUid": null,
"subject": "Following up, {{contact.firstName}}",
"body": "Hi {{contact.firstName}},\n\nStill keen on {{deal.name}}?\n\n{{sender.firstName}}",
"siteId": "site_a1b2c3",
"created": "2026-09-08T09:12:44.120Z",
"updated": "2026-09-08T09:12:44.120Z"
}
FieldTypeNotes
idstringOpaque template id.
objectstringAlways "email_template".
namestringRequired. Trimmed, truncated to 80 characters. Writable.
kindstringtemplate or snippet. template when never set. Writable. A snippet stores no subject.
visibilitystringshared — every CRM editor's — or personal, listed for ownerUid alone. shared when never set. Writable.
ownerUidstring | nullThe member a personal template is listed for. Must be a member of your organization. Required when visibility is personal, refused when it is shared; flipping a template to shared drops it. Writable.
subjectstringThe subject line a template fills in, 200 characters, merge fields allowed. "" when none — an email keeps its own subject. null clears it. Writable.
bodystringRequired. Plain text, 10,000 characters, merge fields allowed; line endings are normalized to \n. Writable.
siteIdstring | nullThe site the template was created from, or null for one written from the organization's own console. Read-only. A template created over the API always names a site.
created / updatedstring | nullISO 8601.

Endpoints

List email templates

GET /v1/email-templates — scope crm:read. Paginated, ordered by template id unless updatedAfter is given. Every template the organization holds, personal ones included: an API key is an organization credential.

ParamNotes
ownerUidPersonal templates listed for this member.
kindtemplate or snippet. Anything else is a 400.
visibilityshared or personal. Anything else is a 400.
updatedAfterTemplates updated after this instant, oldest first — the sync filter.
limit, cursorStandard pagination.
# every shared snippet
curl "https://app.aglyn.com/api/v1/email-templates?kind=snippet&visibility=shared" \
-H "Authorization: Bearer aglyn_sk_…"

One filter narrows the query — in the order listed, so ownerUid before kind — and the rest are checked on the page, which can come back short.

Retrieve an email template

GET /v1/email-templates/{templateId} — scope crm:read. Returns a template, or 404 not_found ("No such email template").

Add an email template

POST /v1/email-templates — scope crm:write. Accepts an Idempotency-Key, scoped to the organization. name, body and consentSiteId are required.

curl -X POST "https://app.aglyn.com/api/v1/email-templates" \
-H "Authorization: Bearer aglyn_sk_…" \
-H "Idempotency-Key: 4c1e9a77-…" \
-H "Content-Type: application/json" \
-d '{"name":"Follow-up","subject":"Following up, {{contact.firstName}}","body":"Hi {{contact.firstName}},\n\nStill keen?","consentSiteId":"site_a1b2c3"}'

Returns 201, or 200 with the original when an Idempotency-Key replays.

Update an email template

PATCH /v1/email-templates/{templateId} — scope crm:write. No Idempotency-Key. An omitted key is left alone, subject: null clears the subject, {} is a no-op.

curl -X PATCH "https://app.aglyn.com/api/v1/email-templates/et_7b2f" \
-H "Authorization: Bearer aglyn_sk_…" \
-H "Content-Type: application/json" \
-d '{"visibility":"personal","ownerUid":"u_9f1c"}'

Delete an email template

DELETE /v1/email-templates/{templateId} — scope crm:write. Accepts an Idempotency-Key, scoped to the organization. Emails already sent from the template are not changed.

{ "id": "et_7b2f", "object": "email_template", "deleted": true }

Errors

StatustypeWhen
400bad_requestcode: "validation_failed" — a missing name, body or consentSiteId, a kind or visibility outside its list, a personal template with no ownerUid or a shared one with one, an ownerUid who is not a member, or a subject/body that is not a string. On the list, a ?kind= or ?visibility= outside its list or a malformed ?updatedAfter=. fields names each key.
403insufficient_scopeKey lacks crm:read / crm:write.
403plan_requiredcode: "crm" — the plan carries no CRM suite.
404not_found"No such email template".
405method_not_allowedAllow: GET, POST on /v1/email-templates, GET, PATCH, DELETE on one template.
409conflictcode: "idempotency_in_progress".

See Conventions → Errors for the shared envelope.

  • Activities — where a sent email is logged, subject and delivery state included.