Transactional email
Send a single email through the REST API.
Use POST /emails for one API-triggered message such as a receipt, invitation,
password reset, OTP, or security notification. Transactional sends appear in
the dashboard’s Transactional log. They do not enroll a contact in a
sequence or use a broadcast audience.
A non-empty workspace mailing address and a configured ESP are still required before SendLit accepts any send. This workspace policy is separate from message content: transactional templates do not render a marketing footer or unsubscribe link.
Create a transactional template
Create a template with purpose: "transactional", or duplicate one of the
built-in transactional starters from the template hub. System templates are
starters and cannot be sent directly; the resulting team-owned identifier
starts with tpl_.
Template responses contain a server-computed requiredVariables list:
{
"templateId": "tpl_...",
"purpose": "transactional",
"requiredVariables": ["customer.name", "otp"]
}The template hub shows these paths and provides ready-to-copy JSON and curl examples.
Send with a template
Nested paths require nested JSON values:
curl -X POST 'http://localhost:5000/emails' \
-H 'content-type: application/json' \
-H 'x-sendlit-apikey: sl_live_...' \
--data '{
"to": "reader@example.com",
"subject": "Your sign-in code",
"templateId": "tpl_...",
"variables": {
"customer": { "name": "Rajat" },
"otp": "345987"
},
"idempotencyKey": "sign-in-123"
}'templateId must identify a team-owned transactional template. A marketing
template is rejected synchronously:
{
"error": "template_not_transactional"
}Required and optional variables
Every unguarded Liquid value must be present before SendLit creates a transactional row or queue job:
Your code is {{ otp }} for {{ customer.name }}.Missing values return:
{
"error": "missing_template_variables",
"missingVariables": ["customer.name", "otp"]
}Use a default filter or a direct if guard for intentionally optional
content:
Hello {{ first_name | default: "there" }}.
{% if promotion %}
Your code: {{ promotion.code }}
{% endif %}address, unsubscribe_link, and subscriber.* are owned by the marketing
pipeline. They are rejected both in transactional template content and as
top-level request variables.
Inline HTML
Provide exactly one of templateId or html. Inline html is sent verbatim:
SendLit does not run Liquid over it, and variables cannot be supplied with it.
This prevents legitimate {{ or {% content in caller-rendered HTML from
being modified.