Sending
to and subject are required, plus either templateId or htmlContent. If you send both, htmlContent is used.
- Liquid. The subject, preheader and body are rendered with Liquid:
{{ data.x }}(also{{ x }}),{{ contact.first_name }},{{ customField.plan }}, and loops. Every value is HTML-escaped.datais limited to 256 KB and 32 levels of nesting. - Idempotency. A repeated
externalIdreturns the original message withdeduplicated: true, and nothing is sent. - Contact. Pass
contactto create or update the recipient first. If the plan’s contact limit blocks that, the email is still sent. The recipient’s language, or thelanguagefield, picks a template translation. - Send policy.
sendPolicy(a key or ID from Settings → Send policies) decides the delivery route and default sender. If you leave it out, the workspace’s Transactional policy applies. That policy delivers to people who unsubscribed from marketing, but never to bounced, complained or erased addresses (422). An unknown policy answers400 SEND_POLICY_NOT_FOUND. - Missing variables. Variables the template marks as required always block a send, and
strict: trueblocks on any unresolved variable. Either way the answer is422 MISSING_VARIABLESwithmissing[]. Unresolved variables that don’t block are returned inwarnings. - Attachments. Up to 20, base64-encoded, at most 3 MB each and 10 MB in total. Also available:
cc/bcc(up to 10 each),replyTo, andfromEmail, which must be on a domain the workspace owns.
Checking before you send
POST /v1/transactional/validate renders exactly as a send would, but sends and stores nothing. It returns the rendered subject, every variable path the template reads, the ones this payload leaves unresolved, and valid: false when a send would be refused. It is useful in CI.
Delivery status
A message moves fromqueued to sent. It then becomes delivered, bounced or complained as the provider reports back, or it ends as failed. Look it up by our ID or by your key:
GET /v1/transactional lists messages newest first. You can filter by to, status and externalId, and page through the results with before / nextBefore.