Skip to main content
POST
Create an email template
Creates a reusable email: a subject and an HTML body_html, both with variables. Attach it to an email step by id, in templates on Add a step. user_id becomes the template’s author, and only the author can change or delete it later. Team admins cannot.

Example

Variables

Variables fill in each contact’s details when the step runs. Write {{key}} in the subject or the body. Build a sequence lists every variable with its name in the app and what it is filled with.
  • Keys are not case-sensitive, and spaces just inside the braces are ignored: {{ First_Name }} works.
  • Values are HTML-escaped in the body, and line breaks in a value become spaces.
  • An AI line is written {{ai:name}} or {{ai:name|what to write}}, with no spaces outside the hint: a name of 1 to 32 lowercase letters, digits and underscores, then an optional hint of up to 200 characters. On a step without personalization, an email with an AI line goes to the rep as a manual_email task instead of being sent.

Fallbacks

{{key|fallback}} uses the fallback when the contact has no value, such as {{first_name|there}}. A fallback is plain text of up to 64 characters, with no braces or line breaks. {{key|}} leaves the value blank on purpose.

When a variable is empty

if_empty decides what happens when a variable is empty for a contact and has no fallback: The hold applies even when the step has personalization on. A template saved before this setting existed has no if_empty and behaves as send. See When a variable is empty.

Variables that are not variables

Every token in double braces is checked when the template is saved. One that is not a variable is refused, so a typo never reaches a prospect:
  • unknown has one entry per distinct token. message is the first entry’s message, and ends with (and N more) when the others say something different.
  • reason is not_a_variable, empty ({{}} or {{custom.}}), fallback_too_long (over 64 characters) or unbalanced (braces that do not pair up, such as {{first_name).
  • suggestion is the closest variable, within two typos, or null. Branch on reason and show message.
  • A custom.<field> is refused until your team has a field with that key or label under People › Settings › Fields, or a contact on the team carries it (a company, for company.custom.<field>). Its suggestion is often null. From the API, add a prospect with custom_fields: [{ "label": "Renewal date", "value": "..." }], which writes the field onto that contact; the template then saves. A company.custom.<field> needs the field in the app, or a company that already has it.
Preview the template before you use it: it shows the rendered text, the variables that came out empty, and the tokens that are not variables.
Templates saved before this check. A template saved earlier can still hold a token that is not a variable. It is no longer sent as typed: each email from it is held as a manual_email task for the rep, with a reason such as Waiting for you: {{account}} isn't a variable, whatever if_empty says. Preview your templates and fix anything listed in unknown.

Files

Responses carry attachments: the files added to the template in the Salesfinity app, each with attachment, file_name, content_type, file_size and url. They go out as download links at the end of an email that starts a thread, and as attachments on a reply. They are read-only here. This API cannot add or remove them, and a template created through it has none.

Subjects

The subject is only sent by an email step that starts a thread: the sequence’s first email step, or a step with new_thread: true. Later steps reply in the same thread, and the prospect sees the thread’s original subject. So a template used only by steps that reply in a thread can leave subject out, or send "". An auto_email step that starts a thread needs a subject on every template it uses: a step that would start one without it is refused with a 400. Without an Idempotency-Key, a retry creates a second template.

Authorizations

x-api-key
string
header
required

Team-scoped API key generated in the Salesfinity dashboard under Settings → Connections → API & Webhooks. A missing or invalid key returns HTTP 403.

Headers

Idempotency-Key
string

Makes this write safe to retry. Send a unique value, such as a UUID, and send the same value again when you retry the same request. A retry with the same key and the same request (method, path including the query string, and JSON body) returns the original successful response without acting twice. The same key with a different body or path returns 409, and so does a retry while the first request is still running; that one is safe to repeat after a moment. A request that fails frees its key, so a retry runs the write again: after a 5xx on a create, confirm with a GET before retrying. Keys are kept for 24 hours and are scoped to your team.

Body

application/json
name
string
required

Template name, 1 to 200 characters.

Maximum string length: 200
Example:

"Follow-up - logistics report"

body_html
string
required

HTML body, 1 to 100,000 characters, with variables filled in for each contact when the step runs. Write {{key}}, or {{key|fallback}} for what to use when the contact has no value (at most 64 characters, with no braces or line breaks; {{key|}} leaves it blank on purpose). Keys are not case-sensitive, and values are HTML-escaped.

  • Person: first_name, last_name, full_name, title, company (the contact's account), email, linkedin.
  • Company, from the contact's company record: company.website, company.industry, company.employees, company.city, company.state, company.country, company.tools.
  • Sender, the rep who owns the enrollment: sender.first_name, sender.last_name, sender.full_name, sender.title, sender.company, sender.phone, sender.meeting_link, sender.linkedin.
  • Custom fields your team has: custom.<key or label> on the contact, company.custom.<key or label> on its company.
  • AI lines: {{ai:name}} or {{ai:name|what to write}}, with no spaces outside the hint, written for each person when the step has personalization on. The name is 1 to 32 lowercase letters, digits and underscores; the hint is optional and at most 200 characters.

Anything else in double braces is refused with 400 and code: unknown_variables.

Maximum string length: 100000
user_id
string
required

The team member creating the template; it becomes the author, the only member who can later change or delete it. Must be an active team member with an active plan or seat. A 24-character hexadecimal ID.

Example:

"507f1f77bcf86cd799439011"

subject
string

Subject line, up to 500 characters. Takes the same variables as body_html, such as {{first_name}}. Only sent by an email step that starts a thread (the first email step, or one with new_thread: true). Leave it out, or send "", for a template used only by steps that reply in a thread.

Maximum string length: 500
Example:

"{{first_name}}, the Q3 logistics numbers"

if_empty
enum<string>
default:wait

What happens when a variable is empty for a contact and has no fallback. wait (the default): the email is held for the rep instead of sent; on an auto_email step it becomes a manual_email task with the reason, such as Waiting for you: no first name, so the rep can fill the gap and send it. send: the email goes out with the gap left blank. null is refused.

Available options:
send,
wait
tags
string[]

Up to 20 labels, each up to 50 characters.

Maximum array length: 20
Maximum string length: 50
archived
boolean

Archiving only affects the archived filter on the list: steps that use the template keep sending it.

Response

The new template.

A reusable email: a subject and an HTML body, with variables.

_id
string

24-character hexadecimal id.

Example:

"507f1f77bcf86cd799439011"

team
string

The team that owns the template (24-character id).

user
string

Author's team member id. Only the author can change or delete the template.

name
string

Template name.

subject
string

Subject line, with variables. Only sent by email steps that start a thread. Empty on a template written for steps that reply in a thread.

body_html
string

HTML body, with variables.

if_empty
enum<string>

What happens when a variable is empty for a contact and has no fallback: wait holds the email for the rep, send sends it with the gap. Absent on a template saved before the setting existed, which behaves as send.

Available options:
send,
wait
attachments
object[]

Files sent with every email from this template, added in the Salesfinity app: as download links at the end of an email that starts a thread, and attached to a reply. Read-only: this API cannot add or remove them.

tags
string[]
archived
boolean

Whether the template is archived. Archiving only affects the archived filter on the list: steps that use it keep sending it, and it can still be attached to steps.

send_count
integer

Emails sent from this template. Rebuilt every 15 minutes.

open_count
integer

Number of opens on emails sent from this template, counted as events. Rebuilt every 15 minutes.

reply_count
integer

Number of replies on emails sent from this template, counted as events. Rebuilt every 15 minutes.

bounce_count
integer

Number of bounces on emails sent from this template, counted as events. Rebuilt every 15 minutes.

click_count
integer

Number of link clicks on emails sent from this template, counted as events. Rebuilt every 15 minutes.

opt_out_count
integer

Number of opt-outs on emails sent from this template. Rebuilt every 15 minutes.

created_at
string<date-time>

When the template was created.

updated_at
string<date-time>

When it last changed.